Syntax of for-loop in SQL Server
Understanding FOR Loops in SQL Server (T-SQL)

Explore the various ways to achieve iterative processing in SQL Server, as T-SQL does not have a direct 'for-loop' construct like other programming languages. Learn about WHILE loops, cursors, and recursive CTEs.
Unlike many procedural programming languages such as C#, Java, or Python, SQL Server's T-SQL dialect does not feature a direct FOR
loop construct. This often leads to confusion for developers new to the SQL Server environment who are accustomed to using FOR
loops for iterative tasks. However, T-SQL provides several powerful alternatives to achieve similar iterative functionality, each with its own use cases and performance considerations. This article will guide you through the common patterns for implementing loops in SQL Server, focusing on WHILE
loops, cursors, and recursive Common Table Expressions (CTEs).
The WHILE Loop: The Closest Equivalent to a FOR Loop
The WHILE
loop is the most direct and frequently used method for iterative processing in T-SQL. It repeatedly executes a block of statements as long as a specified condition is true. You can use it to simulate a FOR
loop by initializing a counter, defining a condition for the loop to continue, and incrementing the counter within the loop body.
DECLARE @counter INT = 1;
DECLARE @max_iterations INT = 10;
WHILE @counter <= @max_iterations
BEGIN
PRINT 'Current iteration: ' + CAST(@counter AS NVARCHAR(10));
-- Perform some operation here
SET @counter = @counter + 1;
END;
Basic WHILE loop simulating a FOR loop from 1 to 10.
WHILE
loop's condition within the loop body (e.g., incrementing a counter) to prevent infinite loops. Use BREAK
to exit the loop prematurely and CONTINUE
to skip the rest of the current iteration and proceed to the next.flowchart TD A[Initialize Counter] --> B{Counter <= Max Iterations?} B -->|Yes| C[Execute Loop Body] C --> D[Increment Counter] D --> B B -->|No| E[End Loop]
Flowchart of a typical WHILE loop structure.
Using Cursors for Row-by-Row Processing
While WHILE
loops are good for general iteration, sometimes you need to process a result set one row at a time. This is where cursors come into play. Cursors allow you to iterate through the rows of a query result set and perform operations on each row individually. However, cursors are generally discouraged due to their performance overhead compared to set-based operations, and should only be used when set-based solutions are not feasible or are overly complex.
DECLARE @ProductName NVARCHAR(100);
DECLARE @ProductID INT;
DECLARE product_cursor CURSOR FOR
SELECT ProductID, ProductName
FROM Production.Products
WHERE CategoryID = 1;
OPEN product_cursor;
FETCH NEXT FROM product_cursor INTO @ProductID, @ProductName;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'Processing Product: ' + @ProductName + ' (ID: ' + CAST(@ProductID AS NVARCHAR(10)) + ')';
-- Perform row-specific operations here
FETCH NEXT FROM product_cursor INTO @ProductID, @ProductName;
END;
CLOSE product_cursor;
DEALLOCATE product_cursor;
Example of using a cursor to iterate through product data.
UPDATE
with JOIN
, INSERT ... SELECT
) over cursors whenever possible. Use cursors only as a last resort for complex, row-by-row logic.Recursive CTEs for Hierarchical or Iterative Data Processing
Recursive Common Table Expressions (CTEs) offer an elegant and often more performant way to handle iterative tasks, particularly when dealing with hierarchical data (like organizational charts or bill of materials) or when you need to generate a sequence of values. A recursive CTE consists of an anchor member (the base case) and a recursive member (the iterative step) that references the CTE itself.
WITH NumberSequence (n)
AS
(
-- Anchor member: Base case
SELECT 1 AS n
UNION ALL
-- Recursive member: Iterative step
SELECT n + 1
FROM NumberSequence
WHERE n < 10
)
-- Final selection from the CTE
SELECT n
FROM NumberSequence
OPTION (MAXRECURSION 0); -- Use 0 for no limit, or a specific number
Recursive CTE generating a sequence of numbers from 1 to 10.
OPTION (MAXRECURSION N)
hint is crucial for recursive CTEs. N
specifies the maximum number of recursion levels. A value of 0
means no limit, but be cautious as this can lead to infinite loops if the recursive condition is not met, potentially exhausting system resources. Always ensure your recursive CTE has a proper termination condition.