游標是結果集的指針,允許逐行處理查詢返回的數據,將集合操作轉化為行級迭代。適用於:必須逐行邏輯、動態 SQL 構建、跨表複雜業務無法集合化時。
DECLARE cursor_name CURSOR [LOCAL | GLOBAL] [FORWARD_ONLY | SCROLL] [STATIC | KEYSET | DYNAMIC | FAST_FORWARD] FOR select_statement;OPEN cursor_name; —— 執行查詢、構建結果集、指針指向第一行之前。FETCH [NEXT | PRIOR | FIRST | LAST | ABSOLUTE n | RELATIVE n] FROM cursor_name INTO @var1, @var2, ...;CLOSE cursor_name; —— 釋放結果集、保留定義。DEALLOCATE cursor_name; —— 釋放定義、內存資源。| 選項 | 行為 | 適用場景 |
|---|---|---|
| FAST_FORWARD | 只進、只讀、優化開銷最小 | 單向遍歷、不更新、性能最優 |
| STATIC | 複製數據到 tempdb,快照隔離 | 需穩定結果集、允許併發修改基表 |
| DYNAMIC | 實時反映基表變更 | 需看到最新數據、開銷最大 |
| KEYSET | 鍵集固定,非鍵列變更可見 | 折中方案 |
| SCROLL | 支持 FIRST/LAST/PRIOR/ABSOLUTE | 需隨機跳轉 |
CREATE TABLE OriginSalary (O_ID NVARCHAR(20) PK, O_Name NVARCHAR(50), O_Salary FLOAT);
CREATE TABLE AddSalary (O_ID NVARCHAR(20) PK, A_Salary FLOAT);
INSERT INTO OriginSalary VALUES ('E01','張三',5000),('E02','李四',6000),('E03','王五',7000);
INSERT INTO AddSalary VALUES ('E01',500),('E02',300),('E03',200);
CREATE PROCEDURE usp_ApplySalaryRaise
AS
BEGIN
SET NOCOUNT ON;
DECLARE @EmpID NVARCHAR(20), @Raise FLOAT;
-- 1. 聲明游標(只進、只讀、高性能)
DECLARE cur_raise CURSOR FAST_FORWARD FOR
SELECT O_ID, A_Salary FROM AddSalary;
-- 2. 打開
OPEN cur_raise;
-- 3. 讀取第一行
FETCH NEXT FROM cur_raise INTO @EmpID, @Raise;
-- 4. 循環處理
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE OriginSalary
SET O_Salary = O_Salary + @Raise
WHERE O_ID = @EmpID;
FETCH NEXT FROM cur_raise INTO @EmpID, @Raise;
END
-- 5. 關閉與釋放
CLOSE cur_raise;
DEALLOCATE cur_raise;
END;
EXEC usp_ApplySalaryRaise;
SELECT * FROM OriginSalary;
/*
O_ID O_Name O_Salary
E01 張三 5500
E02 李四 6300
E03 王五 7200
*/
上述業務完全不需要游標,單條 UPDATE 即可:
UPDATE o
SET o.O_Salary = o.O_Salary + a.A_Salary
FROM OriginSalary o
INNER JOIN AddSalary a ON o.O_ID = a.O_ID;
優勢:單語句、原子性、並行執行計劃、無循環開銷、鎖持有時間極短。
FAST_FORWARD / LOCAL 選項。FETCH NEXT INTO 變量列表 避免 SELECT *。CLOSE/DEALLOCATE。sys.dm_exec_cursors 查看活動游標、cursor_threshold 配置閾值觸發異步填充。