Execute SQL Statement more than once like a For Loop - sql-server

I have a SQL query (normal one). I have to run this query 4 times continuously (like a For Loop in programming). How can I have something like an array and repeat the query execution?
SQL Server
Update :
I am updating some data based on a column TargetLocation. This target location has values from 1 to 5. For each value I need to update the records that have same target location.

If you are running the query in SQL Server Management Studio, then you can use GO N to run a query N times. For example:
insert into MyTable (MyCol) select 'NewRow'
go 4
This will insert 4 rows into MyTable with the text 'NewRow' in them.
If you really need to loop over something in another application, then I recommend using the while loop as suggested by Peter Tirrell.
Note that loops are usually unnecessary in SQL. They may indicate code that is written with procedural logic instead of set-based logic.

Something like a simple SQL WHILE loop?
declare #counter int
set #counter = 0
while #counter < 10
begin
select 'foo'
set #counter = #counter + 1
end

I think you want a join in your UPDATE, as in:
--create two sample tables that we can work on
declare #tabletoupdate table(ID int,TARGETLOCATION int);
declare #sourcetable table(ID int,SOURCELOCATION int);
--drop in sample data
insert into #tabletoupdate select 1,10 union select 2,20 union select 3, 30;
insert into #sourcetable select 1,100 union select 2,200 union select 3, 300;
--see the 'before'
select * from #tabletoupdate
select * from #sourcetable
--make target look like source
update #tabletoupdate
set
targetlocation = s.sourcelocation
from
#tabletoupdate t
inner join #sourcetable s on s.id = t.id;
--show 'after'
select * from #tabletoupdate
select * from #sourcetable
/*
--if you really insist on doing it with a loop
--bad because its
--1) slower
--2) less readable
--3) less reliable when other users are accessing the data
declare #currentID int = 0;
declare #maxID int = (select max(id) from #sourcetable);
while #currentID < #maxID
begin
set #currentID = #currentID + 1;
declare #newval int = (select sourcelocation
from #sourcetable
where id = #currentID
);
if #newval is not null
begin
update #tabletoupdate
set TARGETLOCATION = #newval
where id = #currentID;
end
end
--*/

Related

Multiple select queries execution one after other

I am having six select queries with different where conditions if first select query returns null it should check the next select query and follows. what is the best approach to follow for writing it as stored procedure in SQL server.
You can use ##rowcount
DECLARE #OperatorID INT = 4, #CurrentCalendarView VARCHAR(50) = 'month';
declare #t table (operatorID int, CurrentCalendarView varchar(50));
insert into #t values (2, 'year');
select operatorID - 1, CurrentCalendarView from #t where 1 = 2
if (##ROWCOUNT = 0)
begin
select operatorID + 1, CurrentCalendarView from #t where 1 = 1
end
If I understand your question correctly then you can achieve this like below sample. You can go in this way.
if NOT EXISTS (SELECT TOP(1) 'x' FROM table WHERE id =#myId)
BEGIN
IF NOT EXISTS (SELECT TOP(1) 'x' FROM table2 WHERE id = #myId2)
BEGIN
IF NOT EXISTS (SELECT TOP(1) 'x' FROM table 3 WHERE id = #myID3)
BEGIN
END
END
END

SQL Server : calling a stored procedure using table data

I may be wording this question very poorly but I am not 100% sure what I need to question.
I am trying to iterate over rows in a table and call a stored procedure using the data from the rows.
This is the code I already have, the problem with this is a timing issue (1000 rows takes around 1 minute);
--Set up a temp table with all non email alerts
SELECT TOP(1000)
RowNum = ROW_NUMBER() OVER(ORDER BY AlertID),
a.*, i.ImgData
INTO
#temp
FROM
dbo.ALERTS a
JOIN
dbo.IMAGES i ON i.VehicleID = a.VehicleID
WHERE
a.EmailImageSent = 0 OR a.EmailSent = 0
DECLARE #MaxRownum INT
SET #MaxRownum = (SELECT MAX(RowNum) FROM #temp)
DECLARE #Iter INT
SET #Iter = (SELECT MIN(RowNum) FROM #temp)
DECLARE #ImgData VARBINARY(MAX)
WHILE #Iter <= #MaxRownum
BEGIN
SELECT #VehicleID = VehicleID, #ImgData = ImgData
FROM #temp
WHERE RowNum = #Iter
IF #ImgData IS NOT NULL
BEGIN
EXEC dbo.someProcedure #VehicleID, #ImgData
--SELECT 'Image data found for', #VehicleID, #ImgData
END
SET #Iter = #Iter + 1
END
DROP TABLE #temp
Is there anyway I can run the stored procedure (dbo.someProcedure) while using a set based statement as the input?
Sorry if this has been asked before, I've had a look and couldn't find an answer or if this question isn't informative enough.
Thanks in advance
AFAIK sp_send_dbmail will need to be called once for each email, so either you have a loop here or you have a loop inside dbo.someProcedure.
Still I think that you could make some improvements. Use a FAST_FORWARD cursor rather than creating iteration variables and returning to the table each time to find the next row (thus creating 1000 table scans). Don't store redundant data in your #temp table, only what you need. This makes the table quicker to read.
Try this:
--Set up a temp table with all non email alerts
Create Table #temp (VehicleID int Primary Key Clustered, ImgData varbinary(max));
INSERT INTO #temp (VehicleID, ImgData)
SELECT TOP(1000)
a.VehicleID, i.ImgData
FROM
dbo.ALERTS a
JOIN
dbo.IMAGES i ON i.VehicleID = a.VehicleID
WHERE
a.EmailImageSent = 0 OR a.EmailSent = 0;
DECLARE #VehicleID int;
DECLARE #ImgData VARBINARY(MAX);
DECLARE Alert_Cursor Cursor Fast_Forward For (
Select VehicleID, ImgData From #temp);
OPEN Alert_Cursor;
FETCH NEXT FROM Alert_Cursor INTO #VehicleID, #ImgData;
WHILE ##FETCH_STATUS = 0
BEGIN
IF #ImgData IS NOT NULL
EXEC dbo.someProcedure #VehicleID, #ImgData;
FETCH NEXT FROM Alert_Cursor INTO #VehicleID, #ImgData;
END
CLOSE Alert_Cursor;
DEALLOCATE Alert_Cursor;
DROP TABLE #temp;

Using row count from a temporary table in a while loop SQL Server 2008

I'm trying to create a procedure in SQL Server 2008 that inserts data from a temp table into an already existing table. I think I've pretty much figured it out, I'm just having an issue with a loop. I need the row count from the temp table to determine when the loop should finish.
I've tried using ##ROWCOUNT in two different ways; using it by itself in the WHILE statement, and creating a variable to try and hold the value when the first loop has finished (see code below).
Neither of these methods have worked, and I'm now at a loss as to what to do. Is it possible to use ##ROWCOUNT in this situation, or is there another method that would work better?
CREATE PROCEDURE InsertData(#KeywordList varchar(max))
AS
BEGIN
--create temp table to hold words and weights
CREATE TABLE #tempKeywords(ID int NOT NULL, keyword varchar(10) NOT NULL);
DECLARE #K varchar(10), #Num int, #ID int
SET #KeywordList= LTRIM(RTRIM(#KeywordList))+ ','
SET #Num = CHARINDEX(',', #KeywordList, 1)
SET #ID = 0
--Parse varchar and split IDs by comma into temp table
IF REPLACE(#KeywordList, ',', '') <> ''
BEGIN
WHILE #Num > 0
BEGIN
SET #K= LTRIM(RTRIM(LEFT(#KeywordList, #Num - 1)))
SET #ID = #ID + 1
IF #K <> ''
BEGIN
INSERT INTO #tempKeywords VALUES (#ID, #K)
END
SET #KeywordList = RIGHT(#KeywordList, LEN(#KeywordList) - #Num)
SET #Num = CHARINDEX(',', #KeywordList, 1)
--rowcount of temp table
SET #rowcount = ##ROWCOUNT
END
END
--declaring variables for loop
DECLARE #count INT
DECLARE #t_name varchar(30)
DECLARE #key varchar(30)
DECLARE #key_weight DECIMAL(18,2)
--setting count to start from first keyword
SET #count = 2
--setting the topic name as the first row in temp table
SET #t_name = (Select keyword from #tempKeywords where ID = 1)
--loop to insert data from temp table into Keyword table
WHILE(#count < #rowcount)
BEGIN
SET #key = (SELECT keyword FROM #tempKeywords where ID = #count)
SET #key_weight = (SELECT keyword FROM #tempKeywords where ID = #count+2)
INSERT INTO Keyword(Topic_Name,Keyword,K_Weight)
VALUES(#t_name,#key,#key_weight)
SET #count= #count +2
END
--End stored procedure
END
To solve the second part of your problem:
INSERT INTO Keyword(Topic_Name,Keyword,K_Weight)
SELECT tk1.keyword, tk2.keyword, tk3.keyword
FROM
#tempKeywords tk1
cross join
#tempKeywords tk2
inner join
#tempKeywords tk3
on
tk2.ID = tk3.ID - 1
WHERE
tk1.ID = 1 AND
tk2.ID % 2 = 0
(This code should replace everything in your current script from the --declaring variables for loop comment onwards)
You could change:
WHILE(#count < #rowcount)
to
WHILE(#count < (select count(*) from #tempKeywords))
But like marc_s commented, you should be able to do this without a while loop.
I'd look at reworking your query to see if you can do this in a set based way rather than row by row.
I'm not sure I follow exactly what you are trying to achieve, but I'd be tempted to look at the ROW_NUMBER() function to set the ID of your temp table. Used with a recursive CTE such as shown in this answer you could get an id for each of your non empty trimmed words. An example is something like;
DECLARE #KeywordList varchar(max) = 'TEST,WORD, ,,,LIST, SOME , WITH, SPACES'
CREATE TABLE #tempKeywords(ID int NOT NULL, keyword varchar(10) NOT NULL)
;WITH kws (ord, DataItem, Data) AS(
SELECT CAST(1 AS INT), LEFT(#KeywordList, CHARINDEX(',',#KeywordList+',')-1) ,
STUFF(#KeywordList, 1, CHARINDEX(',',#KeywordList+','), '')
union all
select ord + 1, LEFT(Data, CHARINDEX(',',Data+',')-1),
STUFF(Data, 1, CHARINDEX(',',Data+','), '')
from kws
where Data > ''
), trimKws(ord1, trimkw) AS (
SELECT ord, RTRIM(LTRIM(DataItem))
FROM kws
)
INSERT INTO #tempKeywords (ID, keyword)
SELECT ROW_NUMBER() OVER (ORDER BY ord1) as OrderedWithoutSpaces, trimkw
FROM trimKws WHERE trimkw <> ''
SELECT * FROM #tempKeywords
I don't fully understand what you are trying to acheive with the second part of your query , but but you could just build on this to get the remainder of it working. It certainly looks as though you could do what you are after without while statements at least.

Array like functionality in SQL Server 2008

I want to read EmpID in EMP Table based on some condition. For every EmpID I need to do some operation in another table. How can I read single value of EmpID at a time.
Thanks in advance
UPDATE otherTable...
WHERE table2.EmpID IN (SELECT EMP.EmpID FROM EMP WHERE ...)
try to never loop, work on sets of data.
you can insert, update, delete multiple rows at one time. here in an example insert of multiple rows:
INSERT INTO YourTable
(col1, col2, col3, col4)
SELECT
cola, colb+Colz, colc, #X
FROM ....
LEFT OUTER JOIN ...
WHERE...
you can even insert into multiple tables in a single statement:
INSERT INTO YourTable
(col1, col2, col3, col4)
OUTPUT INSERTED.PK, Inserted.Col2
INTO OtherTable (ColA, ColB)
SELECT
cola, colb+Colz, colc, #X
FROM ....
LEFT OUTER JOIN ...
WHERE...
When looking at a loop see what it done inside it. If it is just inserts/deletes/updates, re-write to use single commands. If there are IFs, see if those can be CASE statements or WHERE conditions on inserts/deletes/updates. If so, remove the loop and use set commands.
I've taken loops and replaced them with the set based commands and reduced the execution time from minutes to a few seconds. I have taken procedures with many nested loops and procedure calls and kept the loops (was impossible to only use inserts/deletes/updates), but I removed the cursor, and have seen less locking/blocking and massive performance boosts as well. Here are two looping methods that are better than cursor loops...
if you have to loop, over a set do something like this:
--this looks up each row for every iteration
DECLARE #msg VARCHAR(250)
DECLARE #hostname sysname
--first select of currsor free loop
SELECT #hostname= min(RTRIM(hostname))
FROM master.dbo.sysprocesses (NOLOCK)
WHERE hostname <> ''
WHILE #hostname is not null
BEGIN
--just some example of some odd task that requires a loop
set #msg='exec master.dbo.xp_cmdshell "net send '
+ RTRIM(#hostname) + ' '
+ 'testing "'
print #msg
--EXEC (#msg) --<<will not actually send the messages
--next select of cursor free loop
SELECT #hostname= min(RTRIM(hostname))
FROM master.dbo.sysprocesses (NOLOCK)
WHERE hostname <> ''
and hostname > #hostname
END
if you have a reasonable set of items (not 100,000) to loop over you can do this:
--this will capture each Key to loop over
DECLARE #msg VARCHAR(250)
DECLARE #From int
DECLARE #To int
CREATE TABLE #Rows --use a table #variable depending on the number of rows to handle
(
RowID int not null primary key identity(1,1)
,hostname varchar(100)
)
INSERT INTO #Rows
SELECT DISTINCT hostname
FROM master.dbo.sysprocesses (NOLOCK)
WHERE hostname <> ''
SELECT #From=0,#To=##ROWCOUNT
WHILE #From<#To
BEGIN
SET #From=#From+1
--just some example of some odd task that requires a loop
SELECT #msg='exec master.dbo.xp_cmdshell "net send '
+ RTRIM(hostname) + ' '
+ 'testing "'
FROM #Rows
WHERE RowID=#From
print #msg
--EXEC (#msg) --<<will not actually send the messages
END
Using a set based approach to SQL logic is always the preferred approach. In this sense DanDan's is an acceptable response.
Alternatively you could use SQL cursors. Although resource heavy they will allow you iterate through a set and apply some logic on each row.
DECLARE #EMPID char(11)
DECLARE c1 CURSOR READ_ONLY
FOR
SELECT EmpID
FROM EMP
WHERE *some_clause*
OPEN c1
FETCH NEXT FROM c1
INTO #EMPID
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #EMPID
FETCH NEXT FROM c1
INTO #EMPID
END
CLOSE c1
DEALLOCATE c1
Generally, you should avoid procedural code in SQL, but if you really need to, use CURSOR:
DECLARE myCursor CURSOR FAST_FORWARD
FOR
SELECT --your SQL query, a regular SQL query.
field1,
field2
FROM
table
OPEN myCursor;
FETCH NEXT FROM myCursor
INTO
#var1, --must be pre-declared, of the same types as field1
#var2
WHILE (##FETCH_STATUS = 0)
BEGIN
--your code use #var1, #var2. Perform queries, do whatever you like.
--It will loop through every row fetched by the query in the beginning of the code, and perform this.
FETCH NEXT FROM myCursor --do this exactly as before the WHILE loop
INTO
#var1,
#var2
END
CLOSE myCursor
Following on from DanDan's Answer, T-SQL allows you to do join in the FROM clause of an UPDATE statement (I can't remember if this is ANSI or not). EG
UPDATE
OtherTable
SET
Auditing = Employees.EmployeeName
FROM
OtherTable
INNER JOIN
Employees ON OtherTable.EmpId = Employees.EmpId
WHERE
Employees.DateStarted > '2010-09-01'

Is there a way to loop through a table variable in TSQL without using a cursor?

Let's say I have the following simple table variable:
declare #databases table
(
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into #databases
Is declaring and using a cursor my only option if I wanted to iterate through the rows? Is there another way?
First of all you should be absolutely sure you need to iterate through each row — set based operations will perform faster in every case I can think of and will normally use simpler code.
Depending on your data it may be possible to loop using just SELECT statements as shown below:
Declare #Id int
While (Select Count(*) From ATable Where Processed = 0) > 0
Begin
Select Top 1 #Id = Id From ATable Where Processed = 0
--Do some processing here
Update ATable Set Processed = 1 Where Id = #Id
End
Another alternative is to use a temporary table:
Select *
Into #Temp
From ATable
Declare #Id int
While (Select Count(*) From #Temp) > 0
Begin
Select Top 1 #Id = Id From #Temp
--Do some processing here
Delete #Temp Where Id = #Id
End
The option you should choose really depends on the structure and volume of your data.
Note: If you are using SQL Server you would be better served using:
WHILE EXISTS(SELECT * FROM #Temp)
Using COUNT will have to touch every single row in the table, the EXISTS only needs to touch the first one (see Josef's answer below).
Just a quick note, if you are using SQL Server (2008 and above), the examples that have:
While (Select Count(*) From #Temp) > 0
Would be better served with
While EXISTS(SELECT * From #Temp)
The Count will have to touch every single row in the table, the EXISTS only needs to touch the first one.
This is how I do it:
declare #RowNum int, #CustId nchar(5), #Name1 nchar(25)
select #CustId=MAX(USERID) FROM UserIDs --start with the highest ID
Select #RowNum = Count(*) From UserIDs --get total number of records
WHILE #RowNum > 0 --loop until no more records
BEGIN
select #Name1 = username1 from UserIDs where USERID= #CustID --get other info from that row
print cast(#RowNum as char(12)) + ' ' + #CustId + ' ' + #Name1 --do whatever
select top 1 #CustId=USERID from UserIDs where USERID < #CustID order by USERID desc--get the next one
set #RowNum = #RowNum - 1 --decrease count
END
No Cursors, no temporary tables, no extra columns.
The USERID column must be a unique integer, as most Primary Keys are.
Define your temp table like this -
declare #databases table
(
RowID int not null identity(1,1) primary key,
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into #databases
Then do this -
declare #i int
select #i = min(RowID) from #databases
declare #max int
select #max = max(RowID) from #databases
while #i <= #max begin
select DatabaseID, Name, Server from #database where RowID = #i --do some stuff
set #i = #i + 1
end
Here is how I would do it:
Select Identity(int, 1,1) AS PK, DatabaseID
Into #T
From #databases
Declare #maxPK int;Select #maxPK = MAX(PK) From #T
Declare #pk int;Set #pk = 1
While #pk <= #maxPK
Begin
-- Get one record
Select DatabaseID, Name, Server
From #databases
Where DatabaseID = (Select DatabaseID From #T Where PK = #pk)
--Do some processing here
--
Select #pk = #pk + 1
End
[Edit] Because I probably skipped the word "variable" when I first time read the question, here is an updated response...
declare #databases table
(
PK int IDENTITY(1,1),
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into #databases
--/*
INSERT INTO #databases (DatabaseID, Name, Server) SELECT 1,'MainDB', 'MyServer'
INSERT INTO #databases (DatabaseID, Name, Server) SELECT 1,'MyDB', 'MyServer2'
--*/
Declare #maxPK int;Select #maxPK = MAX(PK) From #databases
Declare #pk int;Set #pk = 1
While #pk <= #maxPK
Begin
/* Get one record (you can read the values into some variables) */
Select DatabaseID, Name, Server
From #databases
Where PK = #pk
/* Do some processing here */
/* ... */
Select #pk = #pk + 1
End
If you have no choice than to go row by row creating a FAST_FORWARD cursor. It will be as fast as building up a while loop and much easier to maintain over the long haul.
FAST_FORWARD
Specifies a FORWARD_ONLY, READ_ONLY cursor with performance optimizations enabled. FAST_FORWARD cannot be specified if SCROLL or FOR_UPDATE is also specified.
This will work in SQL SERVER 2012 version.
declare #Rowcount int
select #Rowcount=count(*) from AddressTable;
while( #Rowcount>0)
begin
select #Rowcount=#Rowcount-1;
SELECT * FROM AddressTable order by AddressId desc OFFSET #Rowcount ROWS FETCH NEXT 1 ROWS ONLY;
end
Another approach without having to change your schema or using temp tables:
DECLARE #rowCount int = 0
,#currentRow int = 1
,#databaseID int
,#name varchar(15)
,#server varchar(15);
SELECT #rowCount = COUNT(*)
FROM #databases;
WHILE (#currentRow <= #rowCount)
BEGIN
SELECT TOP 1
#databaseID = rt.[DatabaseID]
,#name = rt.[Name]
,#server = rt.[Server]
FROM (
SELECT ROW_NUMBER() OVER (
ORDER BY t.[DatabaseID], t.[Name], t.[Server]
) AS [RowNumber]
,t.[DatabaseID]
,t.[Name]
,t.[Server]
FROM #databases t
) rt
WHERE rt.[RowNumber] = #currentRow;
EXEC [your_stored_procedure] #databaseID, #name, #server;
SET #currentRow = #currentRow + 1;
END
You can use a while loop:
While (Select Count(*) From #TempTable) > 0
Begin
Insert Into #Databases...
Delete From #TempTable Where x = x
End
Lightweight, without having to make extra tables, if you have an integer ID on the table
Declare #id int = 0, #anything nvarchar(max)
WHILE(1=1) BEGIN
Select Top 1 #anything=[Anything],#id=#id+1 FROM Table WHERE ID>#id
if(##ROWCOUNT=0) break;
--Process #anything
END
I really do not see the point why you would need to resort to using dreaded cursor.
But here is another option if you are using SQL Server version 2005/2008
Use Recursion
declare #databases table
(
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
--; Insert records into #databases...
--; Recurse through #databases
;with DBs as (
select * from #databases where DatabaseID = 1
union all
select A.* from #databases A
inner join DBs B on A.DatabaseID = B.DatabaseID + 1
)
select * from DBs
-- [PO_RollBackOnReject] 'FININV10532'
alter procedure PO_RollBackOnReject
#CaseID nvarchar(100)
AS
Begin
SELECT *
INTO #tmpTable
FROM PO_InvoiceItems where CaseID = #CaseID
Declare #Id int
Declare #PO_No int
Declare #Current_Balance Money
While (Select ROW_NUMBER() OVER(ORDER BY PO_LineNo DESC) From #tmpTable) > 0
Begin
Select Top 1 #Id = PO_LineNo, #Current_Balance = Current_Balance,
#PO_No = PO_No
From #Temp
update PO_Details
Set Current_Balance = Current_Balance + #Current_Balance,
Previous_App_Amount= Previous_App_Amount + #Current_Balance,
Is_Processed = 0
Where PO_LineNumber = #Id
AND PO_No = #PO_No
update PO_InvoiceItems
Set IsVisible = 0,
Is_Processed= 0
,Is_InProgress = 0 ,
Is_Active = 0
Where PO_LineNo = #Id
AND PO_No = #PO_No
End
End
It's possible to use a cursor to do this:
create function [dbo].f_teste_loop
returns #tabela table
(
cod int,
nome varchar(10)
)
as
begin
insert into #tabela values (1, 'verde');
insert into #tabela values (2, 'amarelo');
insert into #tabela values (3, 'azul');
insert into #tabela values (4, 'branco');
return;
end
create procedure [dbo].[sp_teste_loop]
as
begin
DECLARE #cod int, #nome varchar(10);
DECLARE curLoop CURSOR STATIC LOCAL
FOR
SELECT
cod
,nome
FROM
dbo.f_teste_loop();
OPEN curLoop;
FETCH NEXT FROM curLoop
INTO #cod, #nome;
WHILE (##FETCH_STATUS = 0)
BEGIN
PRINT #nome;
FETCH NEXT FROM curLoop
INTO #cod, #nome;
END
CLOSE curLoop;
DEALLOCATE curLoop;
end
I'm going to provide the set-based solution.
insert #databases (DatabaseID, Name, Server)
select DatabaseID, Name, Server
From ... (Use whatever query you would have used in the loop or cursor)
This is far faster than any looping techique and is easier to write and maintain.
I prefer using the Offset Fetch if you have a unique ID you can sort your table by:
DECLARE #TableVariable (ID int, Name varchar(50));
DECLARE #RecordCount int;
SELECT #RecordCount = COUNT(*) FROM #TableVariable;
WHILE #RecordCount > 0
BEGIN
SELECT ID, Name FROM #TableVariable ORDER BY ID OFFSET #RecordCount - 1 FETCH NEXT 1 ROW;
SET #RecordCount = #RecordCount - 1;
END
This way I don't need to add fields to the table or use a window function.
I agree with the previous post that set-based operations will typically perform better, but if you do need to iterate over the rows here's the approach I would take:
Add a new field to your table variable (Data Type Bit, default 0)
Insert your data
Select the Top 1 Row where fUsed = 0 (Note: fUsed is the name of the field in step 1)
Perform whatever processing you need to do
Update the record in your table variable by setting fUsed = 1 for the record
Select the next unused record from the table and repeat the process
DECLARE #databases TABLE
(
DatabaseID int,
Name varchar(15),
Server varchar(15),
fUsed BIT DEFAULT 0
)
-- insert a bunch rows into #databases
DECLARE #DBID INT
SELECT TOP 1 #DBID = DatabaseID from #databases where fUsed = 0
WHILE ##ROWCOUNT <> 0 and #DBID IS NOT NULL
BEGIN
-- Perform your processing here
--Update the record to "used"
UPDATE #databases SET fUsed = 1 WHERE DatabaseID = #DBID
--Get the next record
SELECT TOP 1 #DBID = DatabaseID from #databases where fUsed = 0
END
Step1: Below select statement creates a temp table with unique row number for each record.
select eno,ename,eaddress,mobno int,row_number() over(order by eno desc) as rno into #tmp_sri from emp
Step2:Declare required variables
DECLARE #ROWNUMBER INT
DECLARE #ename varchar(100)
Step3: Take total rows count from temp table
SELECT #ROWNUMBER = COUNT(*) FROM #tmp_sri
declare #rno int
Step4: Loop temp table based on unique row number create in temp
while #rownumber>0
begin
set #rno=#rownumber
select #ename=ename from #tmp_sri where rno=#rno **// You can take columns data from here as many as you want**
set #rownumber=#rownumber-1
print #ename **// instead of printing, you can write insert, update, delete statements**
end
This approach only requires one variable and does not delete any rows from #databases. I know there are a lot of answers here, but I don't see one that uses MIN to get your next ID like this.
DECLARE #databases TABLE
(
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into #databases
DECLARE #CurrID INT
SELECT #CurrID = MIN(DatabaseID)
FROM #databases
WHILE #CurrID IS NOT NULL
BEGIN
-- Do stuff for #CurrID
SELECT #CurrID = MIN(DatabaseID)
FROM #databases
WHERE DatabaseID > #CurrID
END
Here's my solution, which makes use of an infinite loop, the BREAK statement, and the ##ROWCOUNT function. No cursors or temporary table are necessary, and I only need to write one query to get the next row in the #databases table:
declare #databases table
(
DatabaseID int,
[Name] varchar(15),
[Server] varchar(15)
);
-- Populate the [#databases] table with test data.
insert into #databases (DatabaseID, [Name], [Server])
select X.DatabaseID, X.[Name], X.[Server]
from (values
(1, 'Roger', 'ServerA'),
(5, 'Suzy', 'ServerB'),
(8675309, 'Jenny', 'TommyTutone')
) X (DatabaseID, [Name], [Server])
-- Create an infinite loop & ensure that a break condition is reached in the loop code.
declare #databaseId int;
while (1=1)
begin
-- Get the next database ID.
select top(1) #databaseId = DatabaseId
from #databases
where DatabaseId > isnull(#databaseId, 0);
-- If no rows were found by the preceding SQL query, you're done; exit the WHILE loop.
if (##ROWCOUNT = 0) break;
-- Otherwise, do whatever you need to do with the current [#databases] table row here.
print 'Processing #databaseId #' + cast(#databaseId as varchar(50));
end
This is the code that I am using 2008 R2. This code that I am using is to build indexes on key fields (SSNO & EMPR_NO) n all tales
if object_ID('tempdb..#a')is not NULL drop table #a
select 'IF EXISTS (SELECT name FROM sysindexes WHERE name ='+CHAR(39)+''+'IDX_'+COLUMN_NAME+'_'+SUBSTRING(table_name,5,len(table_name)-3)+char(39)+')'
+' begin DROP INDEX [IDX_'+COLUMN_NAME+'_'+SUBSTRING(table_name,5,len(table_name)-3)+'] ON '+table_schema+'.'+table_name+' END Create index IDX_'+COLUMN_NAME+'_'+SUBSTRING(table_name,5,len(table_name)-3)+ ' on '+ table_schema+'.'+table_name+' ('+COLUMN_NAME+') ' 'Field'
,ROW_NUMBER() over (order by table_NAMe) as 'ROWNMBR'
into #a
from INFORMATION_SCHEMA.COLUMNS
where (COLUMN_NAME like '%_SSNO_%' or COLUMN_NAME like'%_EMPR_NO_')
and TABLE_SCHEMA='dbo'
declare #loopcntr int
declare #ROW int
declare #String nvarchar(1000)
set #loopcntr=(select count(*) from #a)
set #ROW=1
while (#ROW <= #loopcntr)
begin
select top 1 #String=a.Field
from #A a
where a.ROWNMBR = #ROW
execute sp_executesql #String
set #ROW = #ROW + 1
end
SELECT #pk = #pk + 1
would be better:
SET #pk += #pk
Avoid using SELECT if you are not referencing tables are are just assigning values.

Resources