Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
kalleboo
Jan 13, 2001

Hjälp

nbv4 posted:

I am, I just would like one last line of defence against total query entry, just for piece of mind against anything unforeseen... I tried running through each query once with "LIMIT 0" attached, but that didn't work. I'll look into the transaction thing.
This is the whole point of transactions - to be able to roll back changes if anything goes wrong (well, along with making things atomic and the side effect of certain things being optimizable). With MySQL you need to be using InnoDB and a fairly recent version (5.0 IIRC) for support.

kalleboo fucked around with this message at 12:53 on Feb 7, 2008

Adbot
ADBOT LOVES YOU

nbv4
Aug 21, 2002

by Duchess Gummybuns

kalleboo posted:

This is the whole point of transactions - to be able to roll back changes if anything goes wrong (well, along with making things atomic and the side effect of certain things being optimizable). With MySQL you need to be using InnoDB and a fairly recent version (5.0 IIRC) for support.

I just spent the last hour looking up transactions, and have now got it working with my site. The only problem is that my webhost is using an old version of MySQL so it may not work there :(

edit: basically i have this:

code:
mysql_query("BEGIN");

for($k=0; $k<sizeof($fixed_file); $k++)
{
        $sql="blah query"

        if(!(mysql_query($sql)))
	{
                mysql_query("ROLLBACK");
		die("There was an error in entering data on line <b>{$k+1}</b>");
		
	}
}

mysql_query("COMMIT");
this works in mysql 5, will it work the same way in 4.1.22? Googling around leads me to believe they changed the way it works in mysql 5...

edit2: nevermind, it works

nbv4 fucked around with this message at 13:49 on Feb 7, 2008

chocojosh
Jun 9, 2007

D00D.

Walked posted:

Can someone help me understand:

http://msdn2.microsoft.com/en-us/library/ms186734.aspx

I am not getting what OVER does in this statement - I think I understand the remainder of how the paging works, but I'm somewhat new with SQL and I dont really "get" the OVER clause.

:confused:

edit: Or feel free to suggest me a paging solution for SQL Server 2005 - I'm trying to avoid using the ASP.NET PagedDataSource :downs:

Regarding paging, for .NET 1.1 (what we use at my company) we have some code to return only the approrpiate records because from what I've been told .NET needs to call the stored procedure each time the page index is changed (thus if you have 1 million records and you're displaying 50, you have to get the entire million each time you change a page). I've also been told that this has been remedied in .NET 2.0, but I honestly don't know.

Anyways, the basic idea of our paging solution is to pass in the page number as a parameter to the stored procedure and then use that page number parameter with a predefined page size and the ROW_NUM to determine which page to return.

code:

DECLARE @FirstRec int, @LastRec int
SELECT @FirstRec = (@CurrentPage - 1) * @PageSize
SELECT @LastRec = (@CurrentPage * @PageSize + 1)

SELECT STUFF
FROM TABLE
WHERE ROW_NUM > @FirstRec AND < @LastRec
--I may have messed up the > and < signs.. perhaps > <= instead..
I recommend googling "custom paging asp.net" with the type of ASP.NET control you will be using (i.e. pageddatasource).

The website http://dotnetjunkies.com/Tutorial/EA868776-D71E-448A-BC23-B64B871F967F.dcik is decent except for two modifications I would make to their code:

1) Don't use the Identity column, use the ROW_NUM. It is possible to have gaps in the Identity column after you delete records and then you will get pages that are of different sizes (i.e. page 2 will return records 11-20
2) The code for C# code behind, instead of doing all that stuff about enabling and disabling the next and previous buttons, set the virtualcount property (from the total number of returned records) and the current page index, and the datasource should take care of figuring out what buttons to display.

Walked
Apr 14, 2003

chocojosh posted:

Regarding paging, for .NET 1.1 (what we use at my company) we have some code to return only the approrpiate records because from what I've been told .NET needs to call the stored procedure each time the page index is changed (thus if you have 1 million records and you're displaying 50, you have to get the entire million each time you change a page). I've also been told that this has been remedied in .NET 2.0, but I honestly don't know.

Anyways, the basic idea of our paging solution is to pass in the page number as a parameter to the stored procedure and then use that page number parameter with a predefined page size and the ROW_NUM to determine which page to return.

code:

DECLARE @FirstRec int, @LastRec int
SELECT @FirstRec = (@CurrentPage - 1) * @PageSize
SELECT @LastRec = (@CurrentPage * @PageSize + 1)

SELECT STUFF
FROM TABLE
WHERE ROW_NUM > @FirstRec AND < @LastRec
--I may have messed up the > and < signs.. perhaps > <= instead..
I recommend googling "custom paging asp.net" with the type of ASP.NET control you will be using (i.e. pageddatasource).

The website http://dotnetjunkies.com/Tutorial/EA868776-D71E-448A-BC23-B64B871F967F.dcik is decent except for two modifications I would make to their code:

1) Don't use the Identity column, use the ROW_NUM. It is possible to have gaps in the Identity column after you delete records and then you will get pages that are of different sizes (i.e. page 2 will return records 11-20
2) The code for C# code behind, instead of doing all that stuff about enabling and disabling the next and previous buttons, set the virtualcount property (from the total number of returned records) and the current page index, and the datasource should take care of figuring out what buttons to display.

Thanks, thats a cool way for me to go about it.

Anyone care to offer an explanation of the OVER clause of ROW_NUMBER for me? I'm just not getting what it "does". Is it just more or less a query in which ROW_NUMBER iterates over to "get" row numbers?

npe
Oct 15, 2004
I do know that in oracle, the OVER clause on any analytic function serves to specify the ordering (and optionally the partitioning) of the rows to perform the function on. So yes, you are asking for the row_num according to the ordering in your OVER() clause, which can be different than the ordering of your actual query. This is useful for situations where you need to determine the ranking of results according to one criteria, but are actually interested in returning them according to another.

I don't know MSSQL and it might be different, but I suspect this much is the same.

Walked
Apr 14, 2003

yaoi prophet posted:

I do know that in oracle, the OVER clause on any analytic function serves to specify the ordering (and optionally the partitioning) of the rows to perform the function on. So yes, you are asking for the row_num according to the ordering in your OVER() clause, which can be different than the ordering of your actual query. This is useful for situations where you need to determine the ranking of results according to one criteria, but are actually interested in returning them according to another.

I don't know MSSQL and it might be different, but I suspect this much is the same.

Great, that pretty much explains what I needed to know.

Next question!
Anyone care to suggest a book on database design? "Database Design for Mere Mortals" seems rather good, but want to confirm first.

chocojosh
Jun 9, 2007

D00D.
Is ON DELETE CASCADE evil?

For some reason at my company we don't use ON DELETE CASCADE. I've been told it's to prevent accidental loss of data. On the other hand, there is minor frustration when the database schema gets updated and any stored procedures that deletes the referenced table of the newly added foreign key needs to be modified.

Opinions of experienced database designers/developers?

npe
Oct 15, 2004

chocojosh posted:

Is ON DELETE CASCADE evil?

This question is an easy way to start a pissing match between database developers, from my experience. In my opinion they are in the category of "things we can do if we really need to, but let's try to avoid it". This is because you can easily end up with a byzantine labyrinth of logic consisting of triggers and cascades that is very difficult to follow. Trying to play "guess how this record is getting deleted" is not fun.

Of course, deleting records in general is considered something to avoid for us, so we naturally view automatic deletion with even more suspicion.

Rumsfoord
Jan 29, 2005

Eat or Be Eaten

Walked posted:

Thanks, thats a cool way for me to go about it.

Anyone care to offer an explanation of the OVER clause of ROW_NUMBER for me? I'm just not getting what it "does". Is it just more or less a query in which ROW_NUMBER iterates over to "get" row numbers?

In SQL Server 2005 using the OVER() clause is indicative of a Window function.

I don't ever use them (because we are perpetually years behind state of the art) so I don't know anything about them.

There is plenty on google though if you search for window functions.

There is also a large section about them in a book "SQL Cookbook"
http://www.oreilly.com/catalog/sqlckbk/ if you have access to that O'Reilly safari, or whatever their online library thing is.

Victor
Jun 18, 2004

Walked posted:

Can someone help me understand:

http://msdn2.microsoft.com/en-us/library/ms186734.aspx

I am not getting what OVER does in this statement - I think I understand the remainder of how the paging works, but I'm somewhat new with SQL and I dont really "get" the OVER clause.

:confused:

edit: Or feel free to suggest me a paging solution for SQL Server 2005 - I'm trying to avoid using the ASP.NET PagedDataSource :downs:
TIME entry on row_number()

Victor fucked around with this message at 19:40 on Feb 7, 2008

Walked
Apr 14, 2003

code:
USE test
GO

CREATE PROC spGetBlogPage
	@blogPage int = 1,
	@pageSize int = 2
AS

	
	SELECT *
	FROM
	(
		SELECT id, title, subtitle, body,
		ROW_NUMBER() OVER(ORDER BY id DESC) as row
		FROM blog
	) 
	WHERE row BETWEEN (@blogPage - 1) * (@pageSize + 1) and (@blogPage * @pageSize)
	ORDER BY id DESC
	
Fixed problem number 1!
But anyone know why it's erroring out on the WHERE clause?

Walked fucked around with this message at 03:45 on Feb 8, 2008

Alex007
Jul 8, 2004

Im going out on a limb here, but I think you have to name the result of your inner SELECT if you do something with it (like your WHERE):
code:
	SELECT *
	FROM
	(
		SELECT id, title, subtitle, body,
		ROW_NUMBER() OVER(ORDER BY id DESC) as row
		FROM blog
	) [b]AS MyRows[/b]
	WHERE row BETWEEN (@blogPage - 1) * (@pageSize + 1) and (@blogPage * @pageSize)
	ORDER BY id DESC
	

Jethro
Jun 1, 2000

I was raised on the dairy, Bitch!

Walked posted:

But anyone know why it's erroring out on the WHERE clause?
Try giving the subquery an alias. I.e.
code:
SELECT *
FROM
(
	SELECT id, title, subtitle, body,
	ROW_NUMBER() OVER(ORDER BY id DESC) as row
	FROM blog
) tbl
WHERE row BETWEEN (@blogPage - 1) * (@pageSize + 1) and (@blogPage * @pageSize)
ORDER BY id DESC
	
E:F,B.

Victor
Jun 18, 2004

Walked posted:

Fixed problem number 1!
But anyone know why it's erroring out on the WHERE clause?
Did you see the following comment in my code?
code:
-- the alias is required; silly syntax rules!

Walked
Apr 14, 2003

Victor posted:

Did you see the following comment in my code?
code:
-- the alias is required; silly syntax rules!

Yeah, I missed it because I was pulling from 3 - 4 references at the time.

The alias did it - thanks :)

Victor
Jun 18, 2004
If there's anything my explanation didn't cover, let me know and I'll fix it. I wrote it just for you! :unsmith:

nbv4
Aug 21, 2002

by Duchess Gummybuns
I have a TEXT field that contains comma separated tags. Is it even possible to create a query that returns each unique tag used?

No Safe Word
Feb 26, 2005

nbv4 posted:

I have a TEXT field that contains comma separated tags. Is it even possible to create a query that returns each unique tag used?

If changing your schema to actually have a table of separate tags and setting up a many to many relationship is an option, then do so.

So you basically want to SELECT DISTINCT across essentially the entire list of tags which can only currently be found by splitting a TEXT field on commas? I'd be surprised if there was a way of doing it in one query. You might be able to build a temp table and then do a SELECT DISTINCT on that, but that's the only way I can think of that you'd be able to do that.

nbv4
Aug 21, 2002

by Duchess Gummybuns

No Safe Word posted:

If changing your schema to actually have a table of separate tags and setting up a many to many relationship is an option, then do so.

So you basically want to SELECT DISTINCT across essentially the entire list of tags which can only currently be found by splitting a TEXT field on commas? I'd be surprised if there was a way of doing it in one query. You might be able to build a temp table and then do a SELECT DISTINCT on that, but that's the only way I can think of that you'd be able to do that.

using another table for tags seems like too much work for such a simple tagging system that my project requires. Basically each user owns a bunch of items, and the tags are used to organize and create statistics within that user's items. There will never be a full-table tag search. I'm pretty sure a non-normalized solution is the way to go. I guess if worse comes to worse, I could just do something like:

SELECT DISTINCT tags FROM `planes` WHERE user_id='7'

which would probably return 5 or 6 rows, normally. Then use PHP to separate out the fat and create the list that way...

m5
Oct 1, 2001

nbv4 posted:

using another table for tags seems like too much work for such a simple tagging system that my project requires.

Well, that's the way you do things in SQL.

nbv4
Aug 21, 2002

by Duchess Gummybuns

m5 posted:

Well, that's the way you do things in SQL.

Then how would it be done?

The user types in their tags. PHP splits the string up at the commas. A recursive function goes through each tag, and checks to see if it's already in the database. If it's not, it adds it, then gets the auto_incrimented value and sticks it into the item's 'tags' row. Thats like 5 or 6 queries. Why do it that way when you can just stuff it all into a TEXT column and be done with it? I'm not writing an enterprise level project here where the database has to fulltext through millions of rows. Each tag exists within each user. None of these tags need to exist "globally".

m5
Oct 1, 2001

nbv4 posted:

Then how would it be done?

The user types in their tags. PHP splits the string up at the commas. A recursive function goes through each tag, and checks to see if it's already in the database. If it's not, it adds it, then gets the auto_incrimented value and sticks it into the item's 'tags' row. Thats like 5 or 6 queries. Why do it that way when you can just stuff it all into a TEXT column and be done with it? I'm not writing an enterprise level project here where the database has to fulltext through millions of rows. Each tag exists within each user. None of these tags need to exist "globally".

If the tags are really "structural", then they can be discrete columns along with other stuff about the entity. If there's an uncertain, possibly expanding population of tags and tag values, however, then using another table is the "right" way to do it.

(Aside: why do you say that your tag-checking function is recursive? Are there tags within tags?)

There are a couple of ways to do the SQL, and it's not 5 or 6 queries. Your tag table would have a primary key of its own (probably), and then a column for the main entity ID, plus the tag name and value columns. How you manage the updates would depend on the way you load and save the entity. One possibility is that you load up the entity, manage the tag set as a map, and then save it all back. In that case, your SQL would (in one trip to the database) delete all the existing tag rows and then insert all the updated tags.

You're welcome to jam all your tags together into a string if you like. I've gotten used to always thinking in terms of scalability, because that's the world I know.

No Safe Word
Feb 26, 2005

m5 posted:

If the tags are really "structural", then they can be discrete columns along with other stuff about the entity. If there's an uncertain, possibly expanding population of tags and tag values, however, then using another table is the "right" way to do it.

(Aside: why do you say that your tag-checking function is recursive? Are there tags within tags?)

There are a couple of ways to do the SQL, and it's not 5 or 6 queries. Your tag table would have a primary key of its own (probably), and then a column for the main entity ID, plus the tag name and value columns. How you manage the updates would depend on the way you load and save the entity. One possibility is that you load up the entity, manage the tag set as a map, and then save it all back. In that case, your SQL would (in one trip to the database) delete all the existing tag rows and then insert all the updated tags.

You're welcome to jam all your tags together into a string if you like. I've gotten used to always thinking in terms of scalability, because that's the world I know.
Right, it's all a matter of what will save you the most work and still give you the performance you want. Obviously having to do string parsing like that will be a performance hit any time you need to scan the table for tags, but that may be an acceptable tradeoff for you. Though honestly I don't know what you'd gain in denormalizing it that way if you are indeed scanning the table for tags like that. Typically, from what I understand, denormalization is only a performance gain when you duplicate data in places meaning you don't have to worry about joining and such - all the relevant data is in your table right there. So, if you want to continue just using a string for your tags, then you'd still likely want to create some other table for tag info if you want to relate them to something other than "planes" or whatever table they currently live in.

Stephen
Feb 6, 2004

Stoned
I am trying to query a few tables:
homes and photos (columns id, home_id, and order_id)

Homes can have many photos and is joined by the column home.id = photo.home_id

I would like to get a set of homes with only one photo based on whichever photo has the lowest order_id

If I try:
code:
    SELECT h.home_address , p.id AS 'photo_id' 
    FROM homes h 
    LEFT JOIN photos p ON h.id = p.home_id 
    WHERE h.user_id=1
This will give me repeating results for each photo that a home has.

Can anyone point me to a way that I can have one row per homes result, with a column for the photo linked to it with the lowest order_id field?

Thanks

Victor
Jun 18, 2004
code:
select  h.home_Address, 
        photo_id = p.id
from    homes h
inner join (
    select  home_id,
            order_id = min(order_id)
    from    photos
    group by home_id
) min on min.home_id = h.id
inner join photos p on p.home_id = h.id and p.order_id = min.order_id

Stephen
Feb 6, 2004

Stoned
I changed it to:
code:
select  h.home_address, 
        p.id as photo_id
from    homes h
inner join (
    select  home_id,
            min(order_id) as order_id
    from    photos
    group by home_id
) min on min.home_id = h.id
inner join photos p on p.home_id = h.id and p.order_id = min.order_id
and it works for all results that have a picture row. How can I return the rows that do not have any pictures joined to them as well?

Victor
Jun 18, 2004
code:
inner -> left
:D

Stephen
Feb 6, 2004

Stoned
Perfect. I still have a lot to learn on the joins, but I think I'm in love with you.

Victor
Jun 18, 2004
With SQL2005 row_number() syntax:
code:
with P as (
    select  row_number = row_number() over (partition by home_id order by order_id)
            id,
            home_id
    from    photos
)
select  h.home_Address, 
        photo_id = p.id
from    homes h
left join P p on p.row_number = 1 and p.home_id = h.id

Grigori Rasputin
Aug 21, 2000
WE DON'T NEED ROME TELLING US WHAT TO DO
Does anyone know a good replacement for query analyzer? I'm working in a .NET/SQLServer shop now and find Query Analyzer abysmal to use. I used PL/SQL Developer at my last job as an Oracle dev and found it to be robust, easy to use and cheap. It made it easy to view tables/records/store procedures and had a proper IDE for creating/debugging PL/SQL stored procedures. Basically, it was a stripped down version of TOAD.

Victor
Jun 18, 2004
SQL Server Management Studio? It's not awesome, but it has functional undo/redo, among other things.

ray2k
Feb 7, 2004

Puppet scum beware!

Grigori Rasputin posted:

Does anyone know a good replacement for query analyzer? I'm working in a .NET/SQLServer shop now and find Query Analyzer abysmal to use. I used PL/SQL Developer at my last job as an Oracle dev and found it to be robust, easy to use and cheap. It made it easy to view tables/records/store procedures and had a proper IDE for creating/debugging PL/SQL stored procedures. Basically, it was a stripped down version of TOAD.

You mentioned Query Analyzer which implies Sql Server 2000 and not 2005, so I'll say that that Sql Server Management Studio Express is free and works great with Sql 2000, with the only gotcha that I think some of the script generations may not be 100% compatible with sql 2000. (Not sure on that, though.)

jwnin
Aug 3, 2003
I think the key item here is that if you're a DBA these days, you pretty much also need a copy of Visual Studio to truly round out your toolbox. Management Studio is pretty good, but not all the way there. I don't believe you can debug stored procs without it, and even the BI studio includes a stripped down version. Anything with SQLCLR definitely would benefit from it.

Victor
Jun 18, 2004

ray2k posted:

the only gotcha that I think some of the script generations may not be 100% compatible with sql 2000. (Not sure on that, though.)

wwb
Aug 17, 2004

jwnin posted:

I think the key item here is that if you're a DBA these days, you pretty much also need a copy of Visual Studio to truly round out your toolbox. Management Studio is pretty good, but not all the way there. I don't believe you can debug stored procs without it, and even the BI studio includes a stripped down version. Anything with SQLCLR definitely would benefit from it.

Actually, Management Studio is based on Visual Studio. And the BI tools are visual studio, they just install a limited number of project templates.

quote:

Unless of course you're using SSIS in which case good luck trying to figure out what juju needs to be done to get the parameterization to work right. And if you do figure that out let me know

Well, I did manage to call a parameterized stored proc from a script task once. But that was probably not what you wanted to hear.

No Safe Word
Feb 26, 2005

wwb posted:

Well, I did manage to call a parameterized stored proc from a script task once. But that was probably not what you wanted to hear.
No, yeah, I know how to do that. Sadly, that's easier than doing it the "Right way".

Fart Shark
Jun 17, 2001

AArgh!
AAAAhh!
SQL noob here.

I'm trying to print out a sales report from a daily sales table. It must print out the top selling stores of each month of 1998.

Here is the daily sales table:
code:
daily_sales
store_id: id of the store 
ean_no: id of the specific merchandise
sale_dt: date of the sale
sale_qty: amount sold
The way I tried to do this was using 2 nested sub-queries. The first sub-query returns the monthly sale of each store. The second sub-query tries to get the top selling store from each month. And the top query just prints out the results ordered by month. My problem is in the second sub-query since I can't seem to get the top selling store of each month.

Here is how I tried to do it:
code:
SELECT
	ts.month "Month",
	ts.store_id "Store Number",
	st.store_nm "Store Name",
	sta.state_nm "State",
	CAST(ts.monthly_sale  AS money) "Total Sales Dollars"
FROM
	(SELECT
		ms.month,
		ms.monthly_sale ,
		FIRST( ms.store_id)  AS store_id
	FROM
		(SELECT
			ds.store_id AS store_id,
			MONTH(ds.sale_dt) AS month,
			SUM(mer.unit_price_amt * ds.sale_qty) AS monthly_sale
		FROM
			daily_sales ds
			LEFT JOIN merchandise mer ON ds.ean_no = mer.ean_no
		WHERE
			YEAR(ds.sale_dt) = 1998
		GROUP BY
			ds.store_id,
			MONTH(ds.sale_dt)
		) AS ms
	GROUP BY
		ms.month, ms.monthly_sale
	ORDER BY
		ms.month ASC, ms.monthly_sale DESC
	) AS ts
	LEFT JOIN store st on st.store_id = ts.store_id
	LEFT JOIN state sta on sta.state_cd = st.state_cd
ORDER BY
	ts.month
But the FIRST(column_name) function isn't valid. Any tips?

Ardhanari
Mar 23, 2006

Grigori Rasputin posted:

Does anyone know a good replacement for query analyzer? I'm working in a .NET/SQLServer shop now and find Query Analyzer abysmal to use. I used PL/SQL Developer at my last job as an Oracle dev and found it to be robust, easy to use and cheap. It made it easy to view tables/records/store procedures and had a proper IDE for creating/debugging PL/SQL stored procedures. Basically, it was a stripped down version of TOAD.

I just found this yesterday. It's got its quirks, but still seems to be pretty great. Support looks good too -- I emailed the dev over a couple issues I have with 2005 support and was told to expect a fixed build in a couple days. Pretty sure I'll be buying it (if I can't get my company to) once the evaluation is up.

Victor
Jun 18, 2004
Fart Shark, define "top selling stores". If you need only one record, I showed how to do this above when helping Stephen. What RDBMS are you using?

Adbot
ADBOT LOVES YOU

Fart Shark
Jun 17, 2001

AArgh!
AAAAhh!
I need to return a table that has the top selling stores of each month. Meaning 12 records, 1 per month with the top selling store of that month.

I am using SQL Server 2005

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply