318

What is the syntax of a for loop in TSQL?

Somnath Muluk
  • 55,015
  • 38
  • 216
  • 226
Macho
  • 3,307
  • 3
  • 16
  • 6
  • 1
    It might help if you give a full example of what you're trying to achieve – BugFinder May 20 '11 at 07:57
  • 10
    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. 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
  • 7
    Avoid loops in favour of JOINs and set operations. – Oded May 20 '11 at 07:59
  • 3
    If 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
  • 2
    Sometimes 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 Answers10

447

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
David Ferenczy Rogožan
  • 23,966
  • 9
  • 79
  • 68
TcKs
  • 25,849
  • 11
  • 66
  • 104
  • 24
    Be 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
  • 3
    Also 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
    @Nux: the 0 is set during declaration explicitly – TcKs Oct 27 '14 at 16:15
  • 7
    Yes, but that doesn't work on older SQL Servers (at least not on 2005). – Nux Oct 29 '14 at 13:31
  • 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
244

T-SQL doesn't have a FOR loop, it has a WHILE loop
WHILE (Transact-SQL)

WHILE Boolean_expression
BEGIN

END
Kols
  • 3,641
  • 2
  • 34
  • 42
Amit
  • 21,570
  • 27
  • 74
  • 94
  • 9
    JOINs (and set operations) should be preferred over looping constructs in SQL. – Oded May 20 '11 at 07:58
  • 6
    There 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
  • 1
    It 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
65

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
Dan Cundy
  • 2,649
  • 2
  • 38
  • 65
29

DECLARE @intFlag INT
SET @intFlag = 1
WHILE (@intFlag <=5) 
BEGIN
    PRINT @intFlag
    SET @intFlag = @intFlag + 1
END
GO
Darius Kucinskas
  • 10,193
  • 12
  • 57
  • 79
kashmir
  • 323
  • 3
  • 2
7

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;

Reference

Somnath Muluk
  • 55,015
  • 38
  • 216
  • 226
6

How about this:

BEGIN
   Do Something
END
GO 10

... of course you could put an incremental counter inside it if you need to count.

Alfabravo
  • 7,493
  • 6
  • 46
  • 82
i00
  • 77
  • 1
  • 1
6

Simple answer is NO !!.

There is no FOR in SQL, But you can use WHILE or GOTO to achieve the way how the FOR 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.

Ragul
  • 496
  • 6
  • 20
3

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.

Frobozz
  • 183
  • 8
1

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
Mahesh Mitikiri
  • 126
  • 2
  • 5
0

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;  
Sameer
  • 349
  • 4
  • 12