游標 讓 T-SQL 能逐行處理結果集,適用於需逐行邏輯、動態 SQL、跨表複雜運算等場景。但游標屬行級迴圈,效能遠遜集合操作,能用 JOIN/窗口函數/CTE 解決的堅決不用游標。
| 維度 | 選項 | 特性 |
|---|---|---|
| 作用域 | LOCAL | 僅當前批次/存儲過程可見(預設) |
| GLOBAL | 連線層級可見,跨批次/存儲過程共享,需 DEALLOCATE 釋放 | |
| 捲動性 | FORWARD_ONLY | 僅能 FETCH NEXT 向後(預設,效能最佳) |
| SCROLL | 支援 FIRST/LAST/NEXT/PRIOR/ABSOLUTE/RELATIVE 隨機定位 |
DECLARE cur CURSOR [LOCAL|GLOBAL] [FORWARD_ONLY|SCROLL]
FOR SELECT ...; -- 1. 宣告
OPEN cur; -- 2. 開啟,建立結果集
FETCH NEXT FROM cur INTO @var1, @var2; -- 3. 首次讀取
WHILE @@FETCH_STATUS = 0
BEGIN
-- 處理邏輯
FETCH NEXT FROM cur INTO @var1, @var2; -- 迴圈尾再次讀取
END
CLOSE cur; -- 4. 關閉,釋放結果集鎖定
DEALLOCATE cur; -- 5. 釋放游標結構(全域游標必須)
DECLARE cur CURSOR SCROLL FOR SELECT name, nickname, gender FROM artist;
OPEN cur;
DECLARE @seq INT = 4, @name VARCHAR(20), @nick VARCHAR(50), @gender NCHAR(1);
FETCH ABSOLUTE @seq FROM cur INTO @name, @nick, @gender; -- 直接跳第 4 行
IF @@FETCH_STATUS = 0
PRINT '第4位藝人:' + @name;
CLOSE cur;
DEALLOCATE cur;
-- 批次 1
IF CURSOR_STATUS('global','g_cur') >= 0 DEALLOCATE g_cur;
DECLARE g_cur CURSOR GLOBAL SCROLL FOR SELECT id FROM t;
OPEN g_cur; FETCH ABSOLUTE 10 FROM g_cur INTO @id; CLOSE g_cur;
GO
-- 批次 2(同一連線)
OPEN g_cur; FETCH ABSOLUTE 20 FROM g_cur INTO @id; CLOSE g_cur;
GO
-- 批次 3
DEALLOCATE g_cur;
DECLARE @c CURSOR;
SET @c = CURSOR FOR SELECT name FROM artist;
OPEN @c;
FETCH NEXT FROM @c INTO @name;
PRINT @name;
CLOSE @c; DEALLOCATE @c;
0:成功讀取。-1:超出結果集範圍。-2:目標行已被刪除(動態游標)。CREATE PROC sp_Page
@tbl sysname, @idcol sysname, @page INT, @pagesize INT
AS
BEGIN
DECLARE @sql NVARCHAR(MAX), @start INT, @cnt INT = 0;
SET @sql = N'DECLARE c CURSOR SCROLL FOR SELECT * FROM ' + QUOTENAME(@tbl) +
N' ORDER BY ' + QUOTENAME(@idcol);
EXEC sp_executesql @sql;
OPEN c;
SET @start = (@page - 1) * @pagesize + 1;
FETCH ABSOLUTE @start FROM c; -- 直接定位起始行
WHILE @@FETCH_STATUS = 0 AND @cnt < @pagesize
BEGIN
FETCH NEXT FROM c; -- 這裡需配合 SELECT 列表輸出,簡化示意
SET @cnt += 1;
END
CLOSE c; DEALLOCATE c;
END
注意: 動態 SQL 中宣告的游標屬於該動態批次,外層無法直接 FETCH,生產環境建議改用 OFFSET ... FETCH(SQL Server 2012+)或 ROW_NUMBER() 分頁,完全避免游標。
FAST_FORWARD(FORWARD_ONLY READ_ONLY 優化)較預設快 20-30%。掌握游標語法是為了「知其然並知其所以不為然」,優先選擇集合化思維解決問題。