需逐列處理表資料 (如發送通知、呼叫 API、複雜業務邏輯),集合式操作無法滿足時的兩種主流方案。
DECLARE @Temp TABLE (ID INT IDENTITY(1,1), Name VARCHAR(10));
INSERT INTO @Temp VALUES ('a'),('b'),('c'),('d'),('e');
DECLARE @Id INT, @Name VARCHAR(10);
WHILE EXISTS (SELECT 1 FROM @Temp)
BEGIN
SET ROWCOUNT 1; -- 影響後續 DELETE/INSERT/UPDATE,慎用
SELECT @Id = ID, @Name = Name FROM @Temp;
SET ROWCOUNT 0;
PRINT 'Name: ' + @Name;
-- DELETE FROM @Temp WHERE ID = @Id; -- 若需逐列移除
END
WHILE EXISTS (SELECT 1 FROM @Temp)
BEGIN
SELECT TOP 1 @Id = ID, @Name = Name FROM @Temp;
DELETE FROM @Temp WHERE ID = @Id; -- 必須刪除已處理列,否則無限迴圈
PRINT 'Name: ' + @Name;
END
DECLARE @Temp TABLE (
RowNum INT IDENTITY(1,1), -- 序號
ID INT,
Name VARCHAR(10)
);
INSERT INTO @Temp (ID, Name) VALUES (1,'a'),(2,'b'),(3,'c');
DECLARE @MaxRow INT = (SELECT MAX(RowNum) FROM @Temp), @Cur INT = 1;
WHILE @Cur <= @MaxRow
BEGIN
SELECT @Id = ID, @Name = Name FROM @Temp WHERE RowNum = @Cur;
PRINT 'Name: ' + @Name;
SET @Cur += 1;
END
DECLARE @Temp TABLE (ID INT IDENTITY(1,1), Name VARCHAR(10));
INSERT INTO @Temp VALUES ('a'),('b'),('c'),('d'),('e');
DECLARE @Id INT, @Name VARCHAR(10);
DECLARE Cur CURSOR LOCAL FAST_FORWARD FOR -- 唯讀、順向、最佳化
SELECT ID, Name FROM @Temp;
OPEN Cur;
FETCH NEXT FROM Cur INTO @Id, @Name;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'Name: ' + @Name;
FETCH NEXT FROM Cur INTO @Id, @Name;
END
CLOSE Cur;
DEALLOCATE Cur;
| 指標 | 表變量 WHILE (版本 C) | 游標 (FAST_FORWARD) |
|---|---|---|
| 速度 (萬列基準) | ~1.5 秒 | ~4-6 秒 (慢 2-3 倍) |
| 記憶體 | 較低 | 較高 (游標結構開銷) |
| 並發/鎖定 | 表變量無鎖、無記錄 | 可指定鎖定行為 (READ_ONLY/SCROLL_LOCKS) |
| 功能豐富度 | 僅順向單讀 | 支援捲動、更新、鎖定提示 |
| TempDB 壓力 | 低 | 高 (工作表) |
DECLARE Cur CURSOR
LOCAL -- 區域變數,批次結束自動清理
FAST_FORWARD -- FORWARD_ONLY + READ_ONLY + 優化 (最快)
-- STATIC -- 複製快照,隔離並發修改
-- DYNAMIC -- 即時反映底表變更
-- KEYSET -- 鍵集固定,非鍵值變更可見
FOR SELECT ...;
#Temp「游標是最後手段」非空談。90% 逐列需求可改寫為集合式操作;剩餘 10% 中,表變量 WHILE 多數足夠,游標僅處理極少數複雜邊界情況。