Author |
Topic |
MuadDBA
628 Posts |
Posted - 2006-08-15 : 15:22:46
|
All right, I have a developer who has a query along the lines of:select @var = top 1 var from tablewhile @var is not nullbegin insert into temp_table select top 5 id, address from table2 delete from table where var = @var select @var = top 1 var from tableend Obviously this is not the way to do things, and I know I can eliminate this loop using some sort of modification to the select statement. I know I have seen it before but I can't wrap my head around just how it went. I think it was something like this:select id, address, {some sort of counter} from table2 where {some sort of counter} <=5 group by id, addressright? someone tell me I'm not crazy (despite my username) and help me remember how to do this? |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2006-08-15 : 15:33:29
|
The code makes no sense.It just shuffles data from table2 to temp_table, 5 rows at a time, as long as there are [unique] values left in table table.Most probably the same 5 rows every time.Looks like homework to me.Peter LarssonHelsingborg, Sweden |
 |
|
MuadDBA
628 Posts |
Posted - 2006-08-15 : 15:38:10
|
It's not homework, dude, I have 520 posts here, and a 7 year history as a DBA. The query DOES have a purpose, which you can glean if you look closely. It is looking to take only the top 5 id/address combinations from table2 and move them to temp_table, and it wants to do this once for each id contained in the first table. Sorry I simplified the query so much, the naming convnetions for our table s are pretty whacked. I'll post the real code in just a moment. |
 |
|
rockmoose
SQL Natt Alfen
3279 Posts |
Posted - 2006-08-15 : 15:40:00
|
Along the lines of:select id, address from table twhere (select count(*) from table t2 where t.var = t2.var and t.id <= t2.id) <= 5-- Northwind Example: Last 5 orders (by OrderID desc) per CustomerIDselect t.*from dbo.Orders twhere 5 >= (select count(*) from dbo.Orders t2 where t.CustomerID = t2.CustomerID and t.OrderID <= t2.OrderID )rockmoose |
 |
|
MuadDBA
628 Posts |
Posted - 2006-08-15 : 15:41:41
|
Here's the code:[CODE]select @acc_id = (select top 1 acc_id from #temp)while @acc_id is not nullbegin INSERT INTO #acc_add ( acc_id, add_id ) SELECT TOP 5 acc_id, add_id FROM rj_wrk_ncoa_mar (NOLOCK) WHERE ts = 0 AND acc_id = @acc_id AND sts_cod = 0 AND hh_mtch_addr_info_ncoa_mtch = 'f' AND left(hld_idv_nm, 20) = left(hh_mtch_addr_info_name_on_ncoa, 20) AND hld_idv_nm <> hh_mtch_addr_info_name_on_ncoa delete from #temp where acc_id = @acc_id select @acc_id = (select top 1 acc_id from #temp)end[/CODE]Hopefully it looks less like homework now, and more like I just have a really dumb developer :) |
 |
|
MuadDBA
628 Posts |
Posted - 2006-08-15 : 15:54:41
|
Thank you Mr. Rockmoose SIR!! |
 |
|
rockmoose
SQL Natt Alfen
3279 Posts |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2006-08-16 : 02:48:59
|
There is still a question of which TOP 5 records to be put into #acc_add, since there is no ORDER BY.As of now, TOP 5 is random in the meaning that any index present can force the query and the 5 records. This is not necessary the 5 records you want. To be sure to get the 5 records you want, put an ORDER BY in the select statement.Peter LarssonHelsingborg, Sweden |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2006-08-16 : 02:50:20
|
quote: Originally posted by crazyjoe The query DOES have a purpose, which you can glean if you look closely. It is looking to take only the top 5 id/address combinations from table2 and move them to temp_table, and it wants to do this once for each id contained in the first table.
That purpose was not obvious in the first posting. I am glad you did a follow up posting!Peter LarssonHelsingborg, Sweden |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2006-08-16 : 02:56:00
|
Also try to replace your loop with one single set-based insert like this. Please let me now if it works-- Stage the data for faster processingDECLARE @Stage TABLE (acc_id INT, add_id INT)INSERT @Stage ( acc_id, add_id )SELECT src.acc_id, src.add_idFROM rj_wrk_ncoa_mar src (NOLOCK)INNER JOIN ( SELECT DISTINCT acc_id FROM #Temp ) tmp ON tmp.acc_id = src.acc_idWHERE src.ts = 0 AND src.sts_cod = 0 AND src.hh_mtch_addr_info_ncoa_mtch = 'f' AND LEFT(src.hld_idv_nm, 20) = LEFT(src.hh_mtch_addr_info_name_on_ncoa, 20) AND src.hld_idv_nm <> src.hh_mtch_addr_info_name_on_ncoa-- Do the actual INSERTINSERT #acc_add ( acc_id, add_id )SELECT s.*FROM @Stage sWHERE (SELECT COUNT(*) FROM @Stage s2 WHERE s2.acc_id = s.acc_id AND s2.add_id <= s.add_id) <= 5 Peter LarssonHelsingborg, Sweden |
 |
|
Arnold Fribble
Yak-finder General
1961 Posts |
Posted - 2006-08-16 : 04:25:56
|
Probably worth pointing out that you can do this in 2005 very simply with CROSS APPLY:INSERT INTO #acc_add ( acc_id, add_id )SELECT Acc.acc_id, Add.add_idFROM ( SELECT DISTINCT acc_id FROM #temp WHERE acc_id IS NOT NULL ) AS AccCROSS APPLY ( SELECT TOP 5 add_id FROM rj_wrk_ncoa_mar (NOLOCK) WHERE ts = 0 AND acc_id = Acc.acc_id AND sts_cod = 0 AND hh_mtch_addr_info_ncoa_mtch = 'f' AND left(hld_idv_nm, 20) = left(hh_mtch_addr_info_name_on_ncoa, 20) AND hld_idv_nm <> hh_mtch_addr_info_name_on_ncoa ) AS AddDELETE FROM #temp WHERE acc_id IS NOT NULL Edit: Hmm... those IS NOT NULLs are probably unnecessary since the code you (Joe) posted wouldn't be reliable in the case where #temp.acc_id could be NULL. |
 |
|
|