1. What is a Cursor?
A cursor is a database object used to retrieve, traverse, and manipulate one row at a time from the result set of a query.
Unlike a normal SELECT
query that returns all rows at once, a cursor allows you to process rows individually. This is especially useful when you need to perform row-by-row operations (sometimes called procedural processing) that SQL alone cannot do efficiently.
2. When to Use Cursors
Cursors are used when:
- You need to process each row individually.
- You cannot achieve your goal with set-based operations.
- Performing complex calculations or updates row by row.
- Generating custom reports that require sequential processing.
⚠️ Note: Cursors are usually slower than set-based operations because they process rows one at a time. Only use them when necessary.
3. Cursor Types
Most databases (like SQL Server, Oracle, MySQL) support different types of cursors:
- Implicit Cursors
- Automatically created by SQL when a single-row query is executed.
- Example:
SELECT COUNT(*) FROM Employees;
You don’t manage the cursor yourself.
- Explicit Cursors
- You define and control them.
- Used for multi-row queries when you need to fetch rows one at a time.
4. Cursor Lifecycle
A cursor has 4 main steps:
- Declare the cursor – Define the SQL query.
DECLARE cursor_name CURSOR FOR SELECT column1, column2 FROM table_name WHERE condition;
- Open the cursor – Execute the query and make the result set available.
OPEN cursor_name;
- Fetch rows – Retrieve rows one at a time into variables.
FETCH NEXT FROM cursor_name INTO @var1, @var2;
- Close and deallocate the cursor – Release memory.
CLOSE cursor_name; DEALLOCATE cursor_name;
5. Example in SQL Server
DECLARE @EmployeeID INT, @EmployeeName NVARCHAR(50);
DECLARE EmployeeCursor CURSOR FOR
SELECT EmployeeID, EmployeeName
FROM Employees
WHERE Department = 'Sales';
OPEN EmployeeCursor;
FETCH NEXT FROM EmployeeCursor INTO @EmployeeID, @EmployeeName;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'Employee ID: ' + CAST(@EmployeeID AS NVARCHAR) + ', Name: ' + @EmployeeName;
FETCH NEXT FROM EmployeeCursor INTO @EmployeeID, @EmployeeName;
END
CLOSE EmployeeCursor;
DEALLOCATE EmployeeCursor;
Explanation:
@@FETCH_STATUS
= 0 means the last fetch was successful.- Each row is processed individually inside the loop.
6. Pros and Cons
Pros:
- Can handle complex row-by-row operations.
- Useful for procedural logic in SQL.
Cons:
- Slower than set-based operations.
- Requires careful memory management (open → close → deallocate).