首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 游標完整教學:概念、優缺點、語法與實戰範例

     編輯:關於SqlServer

前言:為什麼需要游標?

關聯式資料庫以集合操作為核心(SET-based),但某些業務邏輯需要逐列處理(Row-by-row,RBAR)。游標就是橋樑:將結果集轉化為可逐列迴圈處理的資料結構。

經典場景:跨表欄位累加

OriginSalary 表:員工薪資 (O_ID, O_Name, O_Salary)
AddSalary 表:加薪額 (O_ID, A_Salary)
需求:O_Salary = O_Salary + A_Salary,逐筆更新 OriginSalary

應用程式寫法

  1. 查詢 JOIN 視圖 → DataSet
  2. 迴圈計算新薪資
  3. 逐筆 UPDATE
  4. 缺點:多次網路往返、應用層邏輯分散、效能差

游標寫法:在資料庫內部完成

游標核心概念

  • 定義:指向結果集的指標,允許逐列存取、更新、刪除
  • 優點:
    • 逐列執行不同邏輯(非整體操作)
    • 基於位置的 UPDATE/DELETE
    • 集合導向 DBMS 與列導向程式設計的橋樑
  • 缺點:
    • 效能通常較集合操作差(RBAR 罰則)
    • 佔用 tempdb、鎖定資源較久
    • 程式碼較冗長、難維護

游標生命週期五步驟

  1. DECLARE:宣告游標
  2. OPEN:開啟游標、執行查詢、建立結果集
  3. FETCH:逐列讀取資料到變數
  4. CLOSE:關閉游標、釋放結果集
  5. DEALLOCATE:釋放游標資源

語法詳解

1. 宣告游標

DECLARE cursor_name CURSOR 
[ LOCAL | GLOBAL ]
[ FORWARD_ONLY | SCROLL ]
[ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ]
[ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ]
FOR select_statement
[ FOR UPDATE [ OF column_list ] ]

關鍵選項

選項說明
INSENSITIVE / STATIC複製資料到 tempdb,隔離基礎表變更,唯讀
SCROLL支援 FIRST/LAST/PRIOR/NEXT/RELATIVE/ABSOLUTE 導航
FORWARD_ONLY僅支援 NEXT,效能最佳(預設)
READ_ONLY不可透過游標更新基礎表

2. 開啟游標

OPEN cursor_name

3. 擷取資料

FETCH [ NEXT | PRIOR | FIRST | LAST | ABSOLUTE n | RELATIVE n ]
FROM cursor_name
INTO @var1, @var2, ...
  • @@FETCH_STATUS:0=成功、-1=失敗/超出範圍、-2=列已刪除
  • 游標開啟後指標在第一列之前,首次 FETCH NEXT 取得第一列

4. 關閉與釋放


CLOSE cursor_name;      -- 釋放結果集,保留定義
DEALLOCATE cursor_name; -- 完全釋放資源

實戰範例:薪資累加更新

步驟 1:建立測試資料


CREATE TABLE OriginSalary (O_ID NVARCHAR(20), O_Name NVARCHAR(50), O_Salary FLOAT);
CREATE TABLE AddSalary (O_ID NVARCHAR(20), A_Salary FLOAT);

INSERT INTO OriginSalary VALUES ('E001', '王小明', 50000), ('E002', '李大華', 45000), ('E003', '陳美麗', 55000);
INSERT INTO AddSalary VALUES ('E001', 5000), ('E002', 3000), ('E003', 4000);

步驟 2:游標儲存程序


CREATE PROCEDURE PK_SalaryAdd
AS
BEGIN
    DECLARE @O_ID NVARCHAR(20), @A_Salary FLOAT;
    
    DECLARE mycursor CURSOR FOR 
        SELECT O_ID, A_Salary FROM AddSalary;
    
    OPEN mycursor;
    FETCH NEXT FROM mycursor INTO @O_ID, @A_Salary;
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        UPDATE OriginSalary 
        SET O_Salary = O_Salary + @A_Salary 
        WHERE O_ID = @O_ID;
        
        FETCH NEXT FROM mycursor INTO @O_ID, @A_Salary;
    END
    
    CLOSE mycursor;
    DEALLOCATE mycursor;
END
GO

步驟 3:執行與驗證


EXEC PK_SalaryAdd;
SELECT * FROM OriginSalary;
-- 結果:王小明 55000、李大華 48000、陳美麗 59000

進階:集合式替代方案(效能更佳)


-- 單一 UPDATE 完成,無需游標
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;

原則:能用集合操作解決,絕不使用游標。游標僅用於:

  • 必須逐列呼叫外部程式/Extended Stored Procedure
  • 複雜邏輯無法用單一 SQL 表達(動態 SQL 建構、條件分支極多)
  • 維護舊系統無法重構時的過渡方案

常見陷阱與最佳實務

  • 忘記 DEALLOCATE:導致記憶體洩漏,連線池耗盡
  • 游標中巢狀游標:效能災難,極力避免
  • 預設選項:明確指定 LOCAL FAST_FORWARD READ_ONLY 獲得最佳效能
  • 交易範圍:游標操作建議包在單一交易中,或明確控制 COMMIT/ROLLBACK 邊界

結語

游標是 SQL Server 提供的強大工具,但「權力越大,責任越大」。理解其運作機制、效能代價、適用邊界,並在可能時優先選擇集合式操作,是資料庫開發者的必修課。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved