DECLARE order_cursor CURSOR FOR SELECT OrderId FROM Orders;
OPEN order_cursor;
FETCH NEXT FROM order_cursor INTO @OrderId;
WHILE @@FETCH_STATUS = 0
BEGIN
-- process each order one at a time
FETCH NEXT FROM order_cursor INTO @OrderId;
END;
CLOSE order_cursor;
DEALLOCATE order_cursor;
Topics
43
Aggregate Functions & GROUP BY
Always On Availability Groups
Backup & Recovery
Change Data Capture (CDC)
Columnstore Indexes
Common Table Expressions (CTEs)
Constraints (Primary Key, Foreign Key, Check & Unique)
Cursors
Data Types & Schema Design
Deadlocks
Dynamic Data Masking
Dynamic SQL
Error Handling with TRY CATCH
Full Text Search
Hash Indexes & Hash Join Operations
Indexes
In-Memory OLTP (Memory-Optimized Tables)
Isolation & Locking
Joins
JSON Support in SQL Server
Linked Servers
Merge Statement (Upsert)
Normalization
Partitioning
Pivoting & Unpivoting Data
Query Optimization & Plans
Query Store
Replication
SQL Server Agent & Job Scheduling
SQL Server Architecture & Editions
SQL Server Profiler & Extended Events
SQL Server Security & Permissions
Stored Procedures & Functions
Subqueries
Temporary Tables & Table Variables
Transactions & ACID
Transparent Data Encryption
Triggers
T-SQL Fundamentals & Syntax
User Defined Functions
Views
Window Functions
XML Data Type & Querying
Cursors
7 questions found
A cursor lets you process a query's results one row at a time, similar to how you might loop through a list in a programming language, but most developers avoid them because SQL Server is optimized for set based operations that work on entire groups of rows at once, and row by row processing with cursors is usually much slower.
Real-world example
A developer initially writes a cursor to update prices one product at a time, then rewrites it as a single set based UPDATE statement, seeing a dramatic performance improvement on a table with thousands of rows.
Stored Procedures & Functions;Query Optimization & Plans
What are the basic steps required to declare, open, use, and properly clean up a cursor?
IntermediateYou declare the cursor with a defining query, open it to begin execution, fetch rows one at a time in a loop while checking the fetch status to know when to stop, and finally close and deallocate the cursor to release the resources it was using, which is an important cleanup step many beginners forget.
DECLARE @ProductId INT;
DECLARE product_cursor CURSOR FOR SELECT ProductId FROM Products;
OPEN product_cursor;
FETCH NEXT FROM product_cursor INTO @ProductId;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT @ProductId;
FETCH NEXT FROM product_cursor INTO @ProductId;
END
CLOSE product_cursor;
DEALLOCATE product_cursor;
Real-world example
A maintenance script processes each product one at a time using a cursor, carefully following the open, fetch, close, and deallocate sequence to avoid leaving unused resources allocated on the server.
Stored Procedures & Functions;Error Handling with TRY CATCH
What are the different cursor types available in SQL Server, such as static, dynamic, and forward only, and how do they differ?
IntermediateA static cursor takes a snapshot of the data when it is opened and does not reflect later changes, a dynamic cursor reflects changes made to the underlying data while the cursor is open, and a forward only cursor, which is often the most efficient, only allows moving forward through the results one row at a time without the ability to go backward.
DECLARE order_cursor CURSOR FORWARD_ONLY STATIC FOR
SELECT OrderId FROM Orders WHERE Status = 'Pending';
Real-world example
A batch process uses a forward only static cursor to process pending orders, since it only needs to move through the results once and does not need to see any orders added by other users while it is running.
Isolation & Locking;Query Optimization & Plans
How would you rewrite a common cursor based row by row update into an equivalent, much faster set based UPDATE statement?
AdvancedYou identify the specific logic being applied to each row inside the cursor's loop, and translate that same logic directly into a single UPDATE statement with an appropriate WHERE clause or JOIN, letting SQL Server's query engine apply the change to every matching row at once instead of looping through them individually.
-- Cursor based approach (slow)
-- Loops through each product, updating price one at a time
-- Set based equivalent (fast)
UPDATE Products
SET Price = Price * 1.1
WHERE Category = 'Electronics';
Real-world example
A team replaces a slow cursor that increased electronics prices by ten percent one row at a time with a single set based UPDATE statement, cutting the operation's runtime from several minutes down to under a second.
Query Optimization & Plans;Stored Procedures & Functions
In what rare situations might using a cursor still be a reasonable choice despite the general recommendation to avoid them?
AdvancedCursors can be reasonable when you need to call an external process, like a stored procedure that sends an email, once for each row individually, when performing complex administrative tasks such as looping through all databases on a server to run maintenance commands, or when a truly row dependent calculation cannot realistically be expressed as a single set based statement.
DECLARE db_cursor CURSOR FOR SELECT name FROM sys.databases WHERE state = 0;
OPEN db_cursor;
FETCH NEXT FROM db_cursor INTO @DbName;
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC ('DBCC CHECKDB (' + @DbName + ')');
FETCH NEXT FROM db_cursor INTO @DbName;
END
Real-world example
A database administrator uses a cursor to loop through every database on a server and run an integrity check command against each one individually, since this kind of administrative task naturally requires acting on one database at a time.
SQL Server Agent & Job Scheduling;Stored Procedures & Functions
What is the performance impact of using a cursor compared to a set based operation on a large table, and why does this difference occur?
IntermediateA cursor processes one row at a time, incurring the overhead of fetching and processing each individual row separately, while a set based operation lets SQL Server's query optimizer work on the entire result set at once, taking advantage of indexes, parallel processing, and efficient execution plans that a row by row loop cannot benefit from.
-- Cursor: processes 100,000 rows one at a time, each with its own overhead
-- Set based: processes all 100,000 rows in a single optimized operation
UPDATE Orders SET Status = 'Archived' WHERE OrderDate < '2020-01-01';
Real-world example
A reporting team notices a cursor based nightly job taking over an hour to process a large orders table, and after converting it to a set based approach, the same task completes in just a few seconds.
Query Optimization & Plans;Indexes
The FAST_FORWARD option creates an optimized, read only, forward only cursor specifically designed for the best possible performance when you only need to read through data once without making any changes, making it a good default choice whenever a cursor truly is the necessary tool for a specific task.
DECLARE report_cursor CURSOR FAST_FORWARD FOR
SELECT OrderId, Amount FROM Orders WHERE Status = 'Completed';
Real-world example
A reporting script that must call an external function once for each completed order uses a FAST_FORWARD cursor to minimize the performance overhead of the row by row processing that is unavoidable in this specific case.
Stored Procedures & Functions;Query Optimization & Plans