What is the syntax of a for
loop in TSQL?

- 55,015
- 38
- 216
- 226

- 3,307
- 3
- 16
- 6
-
1It might help if you give a full example of what you're trying to achieve – BugFinder May 20 '11 at 07:57
-
10SQL is a very different language compared to what you're used to. It's focused on *what*, not *how*. You tell SQL Server what results you want, and let it figure out how to produce the answer. Or, to repharse what I've just said - there isn't a for loop in SQL. – Damien_The_Unbeliever May 20 '11 at 07:58
-
5`WHILE @I < 10; SET @I = @I + 1; BEGIN; ...; END`? However, this should **not** be used for most query processing (but is sometimes required for imperative manipulation). Many such instructions/hints are available on google using the search "tsql for loop". – May 20 '11 at 07:58
-
FYI http://www.databasejournal.com/features/mssql/article.php/3100621/T-SQL-Programming-Part-2---Building-a-T-SQL-Loop.htm – Malachi May 20 '11 at 07:58
-
7Avoid loops in favour of JOINs and set operations. – Oded May 20 '11 at 07:59
-
3If you are not expert in SQL, you should not be considering using a loop. There are only a few conditions where one is needed and most of the rest of the time, using a loop is the equivalent of pushing your car instead of driving it. Learn to think in terms of data sets instead of looping through records. LOoping is an expert level function not because the syntax is hard but because you need to know exactly how much harm you can do with it before you should be allowed to use it. – HLGEM Aug 14 '13 at 21:06
-
2Sometimes it could be used to quickly conjure up test data in a test database that you're just going to delete soon thereafter anyway. In that case, using this removes the need to go through a separate program written in something more like C#, and engineering is not particularly a major concern. Again, I'm just saying this in terms of test data. – Panzercrisis Sep 29 '17 at 13:14
-
@user166390: the `SET...` should go inside `BEGIN ... END` (and `DECLARE @I INT; SET @I = 0` should be prefixed. I see that comment was already edited 3 times ; if s/o has the habilitation to do so, please fix. It provides a valuable quick answer.) – Max Feb 17 '19 at 20:31
-
Does this answer your question? [Do while loop in SQL Server 2008](https://stackoverflow.com/questions/4487546/do-while-loop-in-sql-server-2008) – Michael Freidgeim May 20 '21 at 12:41
10 Answers
There is no for-loop, only the while-loop:
DECLARE @i int = 0
WHILE @i < 20
BEGIN
SET @i = @i + 1
/* do some work */
END

- 23,966
- 9
- 79
- 68

- 25,849
- 11
- 66
- 104
-
24Be it noted that if you intend to use the index in the loop you may want to increment last thing instead of first, depending on your use case. – jinglesthula Mar 04 '13 at 18:24
-
3Also note that default value for local variable is not supported in plain SQL. Hence you need separate `SET @i = 0` before for loop. – Nux Oct 27 '14 at 12:42
-
1
-
7
-
Also, it should be noted that generally work is done before the integer is incremented. A lot of for loops in SQL actually use that integer in their work (iterating from row to row or result to result in temp tables) and may be thrown off if the increment happens at the beginning of the cycle rather than the end. – CSS Feb 03 '16 at 15:22
T-SQL doesn't have a FOR
loop, it has a WHILE
loop
WHILE (Transact-SQL)
WHILE Boolean_expression
BEGIN
END
-
9JOINs (and set operations) should be preferred over looping constructs in SQL. – Oded May 20 '11 at 07:58
-
6There is no limit on stressing (especially for those that are new to SQL), what Damien said: *"SQL is a very different language compared to what you're used to. It's focused on what, not how. You tell SQL Server what results you want, and let it figure out how to produce the answer. "* – ypercubeᵀᴹ May 20 '11 at 08:05
-
1It interesting to note the the MS documentation is wrong here, really. WHILE doesn't take a boolean expression - it takes a predicate - which in addition to being able to evaluate to TRUE or FALSE, could also be UNKNOWN. – Damien_The_Unbeliever May 20 '11 at 08:08
Extra Info
Just to add as no-one has posted an answer that includes how to actually iterate over a dataset inside a loop. You can use the keywords OFFSET FETCH.
Usage
DECLARE @i INT = 0;
SELECT @count= Count(*) FROM {TABLE}
WHILE @i <= @count
BEGIN
SELECT * FROM {TABLE}
ORDER BY {COLUMN}
OFFSET @i ROWS
FETCH NEXT 1 ROWS ONLY
SET @i = @i + 1;
END

- 2,649
- 2
- 38
- 65
-
5
-
2Doesn't that execute the select over and over? Especially if it's a join and can't to go to a specific row number every time? – Leif Neland Oct 06 '21 at 12:36
DECLARE @intFlag INT
SET @intFlag = 1
WHILE (@intFlag <=5)
BEGIN
PRINT @intFlag
SET @intFlag = @intFlag + 1
END
GO

- 10,193
- 12
- 57
- 79

- 323
- 3
- 2
-
14Welcome to Stack Overflow! Would you consider adding some narrative to explain why this code works, and what makes it an answer to the question? This would be very helpful to the person asking the question, and anyone else who comes along. – Andrew Barber Mar 01 '13 at 10:07
-
23
-
7How is this not self explanatory? I had the same question, I understood the answer right away. – DanteTheSmith Oct 02 '17 at 10:01
-
3
For loop is not officially supported yet by SQL server. Already there is answer on achieving FOR Loop's different ways. I am detailing answer on ways to achieve different types of loops in SQL server.
FOR Loop
DECLARE @cnt INT = 0;
WHILE @cnt < 10
BEGIN
PRINT 'Inside FOR LOOP';
SET @cnt = @cnt + 1;
END;
PRINT 'Done FOR LOOP';
If you know, you need to complete first iteration of loop anyway, then you can try DO..WHILE or REPEAT..UNTIL version of SQL server.
DO..WHILE Loop
DECLARE @X INT=1;
WAY: --> Here the DO statement
PRINT @X;
SET @X += 1;
IF @X<=10 GOTO WAY;
REPEAT..UNTIL Loop
DECLARE @X INT = 1;
WAY: -- Here the REPEAT statement
PRINT @X;
SET @X += 1;
IFNOT(@X > 10) GOTO WAY;

- 55,015
- 38
- 216
- 226
-
2This appears to have been copied-pasted-reordered here: https://stackoverflow.com/a/46363319/8239061 – SecretAgentMan Jul 12 '19 at 11:36
-
@SecretAgentMan: Both answers are answering different questions. Additional data given in both answers. – Somnath Muluk Jul 12 '19 at 11:53
-
The questions are not so different. I consider them as duplicates. – Michael Freidgeim May 20 '21 at 12:42
How about this:
BEGIN
Do Something
END
GO 10
... of course you could put an incremental counter inside it if you need to count.
Simple answer is NO !!
.
There is no
FOR
in SQL, But you can useWHILE
orGOTO
to achieve the way how theFOR
will work.
WHILE :
DECLARE @a INT = 10
WHILE @a <= 20
BEGIN
PRINT @a
SET @a = @a + 1
END
GOTO :
DECLARE @a INT = 10
a:
PRINT @a
SET @a = @a + 1
IF @a < = 20
BEGIN
GOTO a
END
I always prefer WHILE
over GOTO
statement.

- 496
- 6
- 20
-
1I like how you mentioned both alternatives instead just 1 like most answers – DanteTheSmith Oct 02 '17 at 10:02
Old thread but still coming up and I thought I would offer a "FOREACH" solution for those that need one.
DECLARE @myValue nvarchar(45);
DECLARE myCursor CURSOR FOR
SELECT [x]
FROM (Values ('Value1'),('Value2'),('Value3'),('Value4'))
as MyTable(x);
OPEN myCursor;
FETCH NEXT FROM myCursor INTO @myValue;
While (@@FETCH_STATUS = 0)
BEGIN
PRINT @myValue
FETCH NEXT FROM myCursor INTO @myValue;
END
CLOSE myCursor;
DEALLOCATE myCursor;
I should state for the record that recursion is frowned upon in the SQL world. And for good reason - it can be very detrimental to performance. Still, for maintenance/offline/bulk/ad-hoc/testing/etc operations, I use this method a lot.

- 183
- 8
Try it, learn it:
DECLARE @r INT = 5
DECLARE @i INT = 0
DECLARE @F varchar(max) = ''
WHILE @i < @r
BEGIN
DECLARE @j INT = 0
DECLARE @o varchar(max) = ''
WHILE @j < @r - @i - 1
BEGIN
SET @o = @o + ' '
SET @j += 1
END
DECLARE @k INT = 0
WHILE @k < @i + 1
BEGIN
SET @o = @o + ' *' -- '*'
SET @k += 1
END
SET @i += 1
SET @F = @F + @o + CHAR(13)
END
PRINT @F
With date:
DECLARE @d DATE = '2019-11-01'
WHILE @d < GETDATE()
BEGIN
PRINT @d
SET @d = DATEADD(DAY,1,@d)
END
PRINT 'n'
PRINT @d

- 126
- 2
- 5
While Loop example in T-SQL which list current month's beginning to end date.
DECLARE @Today DATE= GETDATE() ,
@StartOfMonth DATE ,
@EndOfMonth DATE;
DECLARE @DateList TABLE ( DateLabel VARCHAR(10) );
SET @EndOfMonth = EOMONTH(GETDATE());
SET @StartOfMonth = DATEFROMPARTS(YEAR(@Today), MONTH(@Today), 1);
WHILE @StartOfMonth <= @EndOfMonth
BEGIN
INSERT INTO @DateList
VALUES ( @StartOfMonth );
SET @StartOfMonth = DATEADD(DAY, 1, @StartOfMonth);
END;
SELECT DateLabel
FROM @DateList;

- 349
- 4
- 12