萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

SQL Server 游標完整教學:從語法到分頁存儲過程實戰改造

游標 讓 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. 釋放游標結構(全域游標必須)

SCROLL 游標隨機存取範例

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;

@@FETCH_STATUS 三種狀態

  • 0:成功讀取。
  • -1:超出結果集範圍。
  • -2:目標行已被刪除(動態游標)。

實戰:分頁存儲過程改用 SCROLL 游標

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%。
  • 嚴禁在高併發核心鏈路使用游標。

掌握游標語法是為了「知其然並知其所以不為然」,優先選擇集合化思維解決問題。

copyright © 萬盛學電腦網 all rights reserved