CURSOR concept and usage in SQL - Time & Space Complexity
When using a cursor in SQL, we process rows one by one. Understanding how this affects time helps us see how the work grows as data grows.
We want to know how the time to run the cursor changes when the number of rows increases.
Analyze the time complexity of this cursor usage example.
DECLARE my_cursor CURSOR FOR
SELECT id, name FROM employees;
OPEN my_cursor;
FETCH NEXT FROM my_cursor INTO @id, @name;
WHILE @@FETCH_STATUS = 0
BEGIN
-- Process each row
FETCH NEXT FROM my_cursor INTO @id, @name;
END
CLOSE my_cursor;
DEALLOCATE my_cursor;
This code fetches and processes each employee row one at a time using a cursor.
Look at what repeats as the cursor runs.
- Primary operation: Fetching and processing each row one by one inside the WHILE loop.
- How many times: Once for every row in the employees table.
As the number of rows grows, the cursor does more fetches and processing steps.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 fetch and process steps |
| 100 | About 100 fetch and process steps |
| 1000 | About 1000 fetch and process steps |
Pattern observation: The work grows directly with the number of rows; double the rows, double the work.
Time Complexity: O(n)
This means the time to run the cursor grows in a straight line with the number of rows processed.
[X] Wrong: "Using a cursor is always fast because it handles one row at a time."
[OK] Correct: Processing rows one by one means the total time grows with the number of rows, which can be slow for large data.
Knowing how cursors work and their time cost helps you explain choices in data processing clearly and confidently.
"What if we replaced the cursor with a set-based operation? How would the time complexity change?"
Practice
CURSOR in SQL?Solution
Step 1: Understand what a cursor does
A cursor allows you to handle each row returned by a query individually, instead of all at once.Step 2: Compare options to cursor purpose
Options B, C, and D describe tasks unrelated to row-by-row processing, which is the cursor's main use.Final Answer:
To process query results row by row -> Option AQuick Check:
Cursor = row-by-row processing [OK]
- Thinking cursor speeds up bulk inserts
- Confusing cursor with table creation
- Assuming cursor automates backups
Solution
Step 1: Recall the cursor lifecycle
You first DECLARE the cursor, then OPEN it to start fetching rows, FETCH rows one by one, CLOSE it when done, and finally DEALLOCATE to free resources.Step 2: Match the correct sequence
Only DECLARE, OPEN, FETCH, CLOSE, DEALLOCATE follows this exact order. Other options mix the steps incorrectly.Final Answer:
DECLARE, OPEN, FETCH, CLOSE, DEALLOCATE -> Option CQuick Check:
Cursor lifecycle order = C [OK]
- Opening cursor before declaring
- Fetching before opening
- Not deallocating after closing
DECLARE @Name VARCHAR(50); DECLARE name_cursor CURSOR FOR SELECT Name FROM Employees WHERE Department = 'Sales'; OPEN name_cursor; FETCH NEXT FROM name_cursor INTO @Name; WHILE @@FETCH_STATUS = 0 BEGIN PRINT @Name; FETCH NEXT FROM name_cursor INTO @Name; END CLOSE name_cursor; DEALLOCATE name_cursor;
Assuming the Employees table has Sales department names: 'Alice', 'Bob', 'Carol'.
Solution
Step 1: Understand cursor fetch loop
The cursor fetches each row where Department = 'Sales'. It prints the @Name variable for each fetched row.Step 2: Identify the printed names
Since the table has 'Alice', 'Bob', and 'Carol' in Sales, all three names will be printed one by one.Final Answer:
Alice Bob Carol (each printed on a new line) -> Option DQuick Check:
Cursor prints all fetched rows [OK]
- Assuming only first row prints
- Forgetting to open cursor
- Confusing fetch status check
DECLARE cur CURSOR FOR SELECT Id FROM Products; OPEN cur; FETCH NEXT FROM cur INTO @ProductId; WHILE @@FETCH_STATUS = 0 BEGIN PRINT @ProductId; END CLOSE cur; DEALLOCATE cur;
Solution
Step 1: Check fetch inside loop
The code fetches once before the loop but does not fetch again inside the loop, causing an infinite loop.Step 2: Identify missing statement
To move to next row, FETCH NEXT must be inside the WHILE loop after PRINT.Final Answer:
Missing FETCH NEXT inside the WHILE loop -> Option AQuick Check:
Fetch inside loop needed to advance cursor [OK]
- Forgetting FETCH NEXT inside loop
- Assuming one fetch is enough
- Not opening cursor before fetch
Solution
Step 1: Understand row-by-row update need
When updating salaries individually, you must fetch each employee row and update inside the loop.Step 2: Identify correct cursor usage
Declare cursor for SELECT, open it, fetch each employee, update salary inside loop, close and deallocate correctly declares, opens, fetches, updates inside loop, then closes and deallocates cursor.Final Answer:
Declare cursor for SELECT, open it, fetch each employee, update salary inside loop, close and deallocate -> Option BQuick Check:
Cursor updates row-by-row inside loop [OK]
- Trying to update before opening cursor
- Not fetching rows before update
- Using cursor but updating all at once
Ready to prove it?
Pass the test and this pattern moves unknown
