游標是將 SQL 結果集(多列)轉為程式可逐列處理的核心機制。本文系統說明 DB2 游標四大操作步驟、SQLCODE/SQLSTATE 迴圈控制技巧、WITH HOLD 持久游標特性,並提供標準範本與常見錯誤避坑指南。
DECLARE cursor_name CURSOR FOR
SELECT col1, col2, ...
FROM table
WHERE condition
FOR READ ONLY; -- 唯讀游標效能較佳,避免鎖升級
OPEN cursor_name;
FETCH cursor_name INTO var1, var2, ...;
FETCH 推進一列,將欄位值存入對應變數。FETCH NEXT/FIRST/LAST/PRIOR/ABSOLUTE n/RELATIVE n(捲動游標)。CLOSE cursor_name;
OPEN(重新執行查詢)。DECLARE sqlcode INTEGER DEFAULT 0;
DECLARE v_col1 TYPE;
DECLARE v_col2 TYPE;
DECLARE c1 CURSOR FOR SELECT col1, col2 FROM t1;
OPEN c1;
FETCH c1 INTO v_col1, v_col2;
WHILE sqlcode = 0 DO
-- 處理 v_col1, v_col2
FETCH c1 INTO v_col1, v_col2;
END WHILE;
CLOSE c1;
DECLARE sqlstate CHAR(5) DEFAULT '00000';
-- ...
FETCH c1 INTO v_col1, v_col2;
WHILE sqlstate = '00000' DO
-- 處理
FETCH c1 INTO v_col1, v_col2;
END WHILE;
DECLARE at_end SMALLINT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET at_end = 1;
OPEN c1;
FETCH c1 INTO v_col1, v_col2;
WHILE at_end = 0 DO
-- 處理
FETCH c1 INTO v_col1, v_col2;
END WHILE;
CLOSE c1;
DECLARE c1 CURSOR WITH HOLD FOR SELECT ...;
COMMIT 後不關閉游標,可跨交易繼續 FETCH。ROLLBACK 仍會關閉游標。DECLARE c1 SCROLL CURSOR FOR SELECT ...;
FETCH ABSOLUTE 10、FETCH PRIOR 等隨機存取。SCROLL,資源消耗較大。| 錯誤現象 | 原因 | 修正 |
|---|---|---|
| FETCH 後未檢查狀態直接處理變數 | 最後一次 FETCH 失敗,變數殘留舊值 | 務必在 WHILE 條件或 HANDLER 中判斷 |
| 忘記 CLOSE 游標 | 資源洩漏、鎖持有過久 | 在離開範圍前(含例外分支)必呼叫 CLOSE |
| COMMIT 後續 FETCH 失敗 | 非 WITH HOLD 游標被 COMMIT 關閉 | 宣告時加 WITH HOLD |
| 巢狀迴圈使用同一游標變數 | 內層 CLOSE 影響外層 | 使用不同游標名稱 |
BEGIN
DECLARE v_id INTEGER;
DECLARE v_name VARCHAR(50);
DECLARE at_end SMALLINT DEFAULT 0;
DECLARE c1 CURSOR WITH HOLD FOR
SELECT id, name FROM employees WHERE dept = 'IT' FOR READ ONLY;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET at_end = 1;
OPEN c1;
FETCH c1 INTO v_id, v_name;
WHILE at_end = 0 DO
-- 業務邏輯
CALL process_emp(v_id, v_name);
-- 若需逐筆 COMMIT
COMMIT;
FETCH c1 INTO v_id, v_name;
END WHILE;
CLOSE c1;
END;
掌握游標「宣告→開啟→擷取→關閉」標準流程、善用 CONTINUE HANDLER 取代 SQLCODE 判斷、關鍵場景加上 WITH HOLD,即能編寫高可靠、高效能的 DB2 游標程式碼。