Reputation: 13602
How do I loop through a set of records from a select statement?
Say I have a few records that I wish to loop through and do something with each record. Here's a primitive version of my select statement:
select top 1000 * from dbo.table
where StatusID = 7
Upvotes: 221
Views: 785687
Reputation: 37
I think this is the easy way example to iterate item.
You can change YOURTABLE or YOURCOLUMN to what you want.
declare @cateid int
select YOURCOLUMN into [#TempTable] from YOURTABLE
while (select count(*) from #TempTable) > 0
begin
select top 1 @column = YOURCOLUMN from #TempTable
print(@column)
--DO SOMETHING HERE
delete #TempTable where YOURCOLUMN = @column
end
drop table #TempTable
Upvotes: 0
Reputation: 776
Here is a small improvement to the top-voted answer from FloChanz: Use only ONE "FETCH" statement. That way it is easier to add a new column, and you avoid accidentally having the FETCH do two different things:
/*
create table my_table (yourfield varchar(100), statusid int)
insert into my_Table select 'abc', 7
insert into my_Table select 'pdq', 6
insert into my_Table select 'xyz', 7
*/
DECLARE @MyCursor CURSOR;
DECLARE @MyField varchar(100);
DECLARE @finished bit = 0
BEGIN
SET @MyCursor = CURSOR FOR
select top 1000 YourField from dbo.my_table
where StatusID = 7
OPEN @MyCursor
while @finished = 0 begin
FETCH NEXT FROM @MyCursor
INTO @MyField
if @@FETCH_STATUS = 0
BEGIN
/*
YOUR ALGORITHM GOES HERE
*/
print @MyField
end else begin
set @finished = 1
END;
END;
CLOSE @MyCursor ;
DEALLOCATE @MyCursor;
END;
Upvotes: 1
Reputation: 4934
This is what I've been doing if you need to do something iterative... but it would be wise to look for set operations first. Also, do not do this because you don't want to learn cursors.
select top 1000 TableID
into #ControlTable
from dbo.table
where StatusID = 7
declare @TableID int
while exists (select * from #ControlTable)
begin
select top 1 @TableID = TableID
from #ControlTable
order by TableID asc
-- Do something with your TableID
delete #ControlTable
where TableID = @TableID
end
drop table #ControlTable
Upvotes: 157
Reputation: 769
By using cursor you can easily iterate through records individually and print records separately or as a single message including all the records.
DECLARE @CustomerID as INT;
declare @msg varchar(max)
DECLARE @BusinessCursor as CURSOR;
SET @BusinessCursor = CURSOR FOR
SELECT CustomerID FROM Customer WHERE CustomerID IN ('3908745','3911122','3911128','3911421')
OPEN @BusinessCursor;
FETCH NEXT FROM @BusinessCursor INTO @CustomerID;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @msg = '{
"CustomerID": "'+CONVERT(varchar(10), @CustomerID)+'",
"Customer": {
"LastName": "LastName-'+CONVERT(varchar(10), @CustomerID) +'",
"FirstName": "FirstName-'+CONVERT(varchar(10), @CustomerID)+'",
}
}|'
print @msg
FETCH NEXT FROM @BusinessCursor INTO @CustomerID;
END
Upvotes: 27
Reputation: 579
Small change to sam yi's answer (for better readability):
select top 1000 TableID
into #ControlTable
from dbo.table
where StatusID = 7
declare @TableID int
while exists (select * from #ControlTable)
begin
select @TableID = (select top 1 TableID
from #ControlTable
order by TableID asc)
-- Do something with your TableID
delete #ControlTable
where TableID = @TableID
end
drop table #ControlTable
Upvotes: 49
Reputation: 1001
You could choose to rank your data and add a ROW_NUMBER and count down to zero while iterate your dataset.
-- Get your dataset and rank your dataset by adding a new row_number
SELECT TOP 1000 A.*, ROW_NUMBER() OVER(ORDER BY A.ID DESC) AS ROW
INTO #TEMPTABLE
FROM DBO.TABLE AS A
WHERE STATUSID = 7;
--Find the highest number to start with
DECLARE @COUNTER INT = (SELECT MAX(ROW) FROM #TEMPTABLE);
DECLARE @ROW INT;
-- Loop true your data until you hit 0
WHILE (@COUNTER != 0)
BEGIN
SELECT @ROW = ROW
FROM #TEMPTABLE
WHERE ROW = @COUNTER
ORDER BY ROW DESC
--DO SOMTHING COOL
-- SET your counter to -1
SET @COUNTER = @ROW -1
END
DROP TABLE #TEMPTABLE
Upvotes: 8
Reputation: 3429
By using T-SQL and cursors like this :
DECLARE @MyCursor CURSOR;
DECLARE @MyField YourFieldDataType;
BEGIN
SET @MyCursor = CURSOR FOR
select top 1000 YourField from dbo.table
where StatusID = 7
OPEN @MyCursor
FETCH NEXT FROM @MyCursor
INTO @MyField
WHILE @@FETCH_STATUS = 0
BEGIN
/*
YOUR ALGORITHM GOES HERE
*/
FETCH NEXT FROM @MyCursor
INTO @MyField
END;
CLOSE @MyCursor ;
DEALLOCATE @MyCursor;
END;
Upvotes: 294
Reputation: 2451
this way we can iterate into table data.
DECLARE @_MinJobID INT
DECLARE @_MaxJobID INT
CREATE TABLE #Temp (JobID INT)
INSERT INTO #Temp SELECT * FROM DBO.STRINGTOTABLE(@JobID,',')
SELECT @_MinJID = MIN(JobID),@_MaxJID = MAX(JobID) FROM #Temp
WHILE @_MinJID <= @_MaxJID
BEGIN
INSERT INTO Mytable
(
JobID,
)
VALUES
(
@_MinJobID,
)
SET @_MinJID = @_MinJID + 1;
END
DROP TABLE #Temp
STRINGTOTABLE is user define function which will parse comma separated data and return table. thanks
Upvotes: 1
Reputation: 613
Just another approach if you are fine using temp tables.I have personally tested this and it will not cause any exception (even if temp table does not have any data.)
CREATE TABLE #TempTable
(
ROWID int identity(1,1) primary key,
HIERARCHY_ID_TO_UPDATE int,
)
--create some testing data
--INSERT INTO #TempTable VALUES(1)
--INSERT INTO #TempTable VALUES(2)
--INSERT INTO #TempTable VALUES(4)
--INSERT INTO #TempTable VALUES(6)
--INSERT INTO #TempTable VALUES(8)
DECLARE @MAXID INT, @Counter INT
SET @COUNTER = 1
SELECT @MAXID = COUNT(*) FROM #TempTable
WHILE (@COUNTER <= @MAXID)
BEGIN
--DO THE PROCESSING HERE
SELECT @HIERARCHY_ID_TO_UPDATE = PT.HIERARCHY_ID_TO_UPDATE
FROM #TempTable AS PT
WHERE ROWID = @COUNTER
SET @COUNTER = @COUNTER + 1
END
IF (OBJECT_ID('tempdb..#TempTable') IS NOT NULL)
BEGIN
DROP TABLE #TempTable
END
Upvotes: 9