游標讓你能逐列處理結果集,適用於必須依序、逐筆執行邏輯的情境 (如呼叫外部 API、複雜條件判斷)。但集合導向 (Set-based) 寫法通常效能更好,能用單一 SQL 解決時優先避免游標。
DECLARE cursor_name CURSOR [LOCAL | GLOBAL]
[FORWARD_ONLY | SCROLL]
[STATIC | KEYSET | DYNAMIC | FAST_FORWARD]
[READ_ONLY | SCROLL_LOCKS | OPTIMISTIC]
FOR select_statement;
OPEN cursor_name;
FETCH NEXT FROM cursor_name INTO @var1, @var2, ...;
WHILE @@FETCH_STATUS = 0
BEGIN
-- 處理邏輯
FETCH NEXT FROM cursor_name INTO @var1, @var2, ...;
END
CLOSE cursor_name;
DEALLOCATE cursor_name;
情境:OriginSalary (原薪資) + AddSalary (調薪) → 更新回 OriginSalary。
UPDATE o
SET o.O_Salary = o.O_Salary + a.A_Salary
FROM OriginSalary o
JOIN AddSalary a ON o.O_ID = a.O_ID;
DECLARE @empId NVARCHAR(20), @addSal FLOAT;
DECLARE cur CURSOR LOCAL FAST_FORWARD READ_ONLY FOR
SELECT O_ID, A_Salary FROM AddSalary;
OPEN cur;
FETCH NEXT FROM cur INTO @empId, @addSal;
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE OriginSalary
SET O_Salary = O_Salary + @addSal
WHERE O_ID = @empId;
FETCH NEXT FROM cur INTO @empId, @addSal;
END
CLOSE cur;
DEALLOCATE cur;
| 類型 | 特性 | 適用場景 |
|---|---|---|
| FAST_FORWARD | 唯前向、唯讀、最佳效能 | 單向掃描、不需更新 |
| STATIC | 結果集快照、不反映後續異動 | 需固定資料集、可捲動 |
| KEYSET | 鍵值固定、非鍵值異動可見 | 需捲動且反映資料變更 |
| DYNAMIC | 完全反映所有異動、成本最高 | 極少見,真正需要即時性 |
UPDATE ... JOIN、MERGE、CROSS APPLY、窗函數、Table-Valued Parameter。LOCAL FAST_FORWARD READ_ONLY、盡早 DEALLOCATE。DEALLOCATE 導致記憶體洩漏。COMMIT 導致游標失效 (隱含 CLOSE)。GLOBAL 游標污染連線池。掌握游標原理,但請讓「集合思維」成為預設選擇。