FETCH是從游標結果集逐行提取資料的唯一指令。每次執行推進內部指標至下一行,將欄位值賦予目標變數。語法結構:
FETCH cursor_name INTO variable[, variable,...];
%NOTFOUND或%FOUND判斷提取結果OPEN c_emp;
FETCH c_emp INTO v_ename, v_salary; -- 第1行
DBMS_OUTPUT.PUT_LINE(...);
FETCH c_emp INTO v_ename, v_salary; -- 第2行
DBMS_OUTPUT.PUT_LINE(...);
FETCH c_emp INTO v_ename, v_salary; -- 第3行
DBMS_OUTPUT.PUT_LINE(...);
CLOSE c_emp;
缺點:程式碼冗長、行數固定、維護困難、易出錯。
SET SERVEROUTPUT ON
DECLARE
v_ename EMP.ENAME%TYPE;
v_salary EMP.SALARY%TYPE;
CURSOR c_emp IS SELECT ename, salary FROM emp;
BEGIN
OPEN c_emp;
LOOP
FETCH c_emp INTO v_ename, v_salary;
EXIT WHEN c_emp%NOTFOUND; -- 核心:自動適應任意行數
DBMS_OUTPUT.PUT_LINE('Salary of Employee ' || v_ename || ' is ' || v_salary);
END LOOP;
CLOSE c_emp;
END;
優點:簡潔通用、自動適應結果集大小、可讀性強、易於擴展業務邏輯。
適用於大量資料(>1000行),大幅減少SQL/PLSQL引擎切換:
DECLARE
TYPE emp_tab_type IS TABLE OF emp%ROWTYPE;
v_emp_tab emp_tab_type;
CURSOR c_emp IS SELECT * FROM emp;
BEGIN
OPEN c_emp;
FETCH c_emp BULK COLLECT INTO v_emp_tab LIMIT 100; -- 分批提取
FOR i IN 1..v_emp_tab.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(v_emp_tab(i).ename);
END LOOP;
CLOSE c_emp;
END;
Oracle自動處理OPEN/FETCH/CLOSE,最簡潔:
BEGIN
FOR rec IN (SELECT ename, salary FROM emp) LOOP
DBMS_OUTPUT.PUT_LINE('Salary of Employee ' || rec.ename || ' is ' || rec.salary);
END LOOP;
END;
注意:無法控制提取過程、無法使用%ROWCOUNT等屬性、不適用於需FOR UPDATE的場景。
| 場景 | 推薦模式 | 關鍵參數 |
|---|---|---|
| 小量資料(<100行) | 游標FOR迴圈 | 簡潔優先 |
| 中量資料(100-10000行) | 顯式游標+LOOP | 靈活控制、可用%ROWCOUNT分批提交 |
| 大量資料(>10000行) | BULK COLLECT + FORALL | LIMIT 100-1000,配合FORALL批量DML |
| 需UPDATE/DELETE當前行 | 顯式游標+FOR UPDATE | WHERE CURRENT OF精準定位 |
FETCH是游標操作的核心,掌握「單行提取→迴圈化→批量提取」三層演進,根據資料量與業務複雜度選擇適當模式。實務中建議:預設使用游標FOR迴圈,需精細控制時用顯式游標,大數據量必須上BULK COLLECT。