Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2000 Forums
 Transact-SQL (2000)
 Eliminating a loop, need help....

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 table
while @var is not null
begin
insert into temp_table select top 5 id, address from table2
delete from table where var = @var
select @var = top 1 var from table
end


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, address

right? 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 Larsson
Helsingborg, Sweden
Go to Top of Page

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.
Go to Top of Page

rockmoose
SQL Natt Alfen

3279 Posts

Posted - 2006-08-15 : 15:40:00
Along the lines of:

select id, address from table t
where (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 CustomerID
select t.*
from dbo.Orders t
where 5 >= (select count(*) from dbo.Orders t2 where t.CustomerID = t2.CustomerID and t.OrderID <= t2.OrderID )


rockmoose
Go to Top of Page

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 null

begin

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 :)
Go to Top of Page

MuadDBA

628 Posts

Posted - 2006-08-15 : 15:54:41
Thank you Mr. Rockmoose SIR!!
Go to Top of Page

rockmoose
SQL Natt Alfen

3279 Posts

Posted - 2006-08-15 : 17:06:49
See also #2 in this blog:

http://weblogs.sqlteam.com/mladenp/archive/2005/08/01/7421.aspx

Go to Top of Page

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 Larsson
Helsingborg, Sweden
Go to Top of Page

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 Larsson
Helsingborg, Sweden
Go to Top of Page

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 processing
DECLARE @Stage TABLE (acc_id INT, add_id INT)

INSERT @Stage
(
acc_id,
add_id
)
SELECT src.acc_id,
src.add_id
FROM rj_wrk_ncoa_mar src (NOLOCK)
INNER JOIN (
SELECT DISTINCT acc_id
FROM #Temp
) tmp ON tmp.acc_id = src.acc_id
WHERE 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 INSERT
INSERT #acc_add
(
acc_id,
add_id
)
SELECT s.*
FROM @Stage s
WHERE (SELECT COUNT(*) FROM @Stage s2 WHERE s2.acc_id = s.acc_id AND s2.add_id <= s.add_id) <= 5

Peter Larsson
Helsingborg, Sweden
Go to Top of Page

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_id
FROM ( SELECT DISTINCT acc_id FROM #temp WHERE acc_id IS NOT NULL ) AS Acc
CROSS 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 Add

DELETE 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.
Go to Top of Page
   

- Advertisement -