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

Oracle 游標四大核心屬性深度解析:%FOUND、%NOTFOUND、%ROWCOUNT、%ISOPEN 實戰應用

     編輯:Oracle 資料庫基礎

游標屬性速查表

屬性適用對象回傳型別意義初始值
%FOUND顯式/隱式游標BOOLEAN最近 FETCH/DML 找到/影響資料NULL(未執行前)
%NOTFOUND顯式/隱式游標BOOLEAN最近 FETCH/DML 未找到/未影響資料NULL
%ROWCOUNT顯式/隱式游標NUMBER已擷取/影響列數累計0
%ISOPEN顯式游標/游標變數BOOLEAN游標是否開啟中FALSE

屬性行為時序圖

顯式游標生命週期:
宣告 → %ISOPEN=FALSE, %ROWCOUNT=0, %FOUND=NULL, %NOTFOUND=NULL
  ↓ OPEN
%ISOPEN=TRUE
  ↓ FETCH (第1列)
%ROWCOUNT=1, %FOUND=TRUE, %NOTFOUND=FALSE
  ↓ FETCH (第N列)
%ROWCOUNT=N, %FOUND=TRUE, %NOTFOUND=FALSE
  ↓ FETCH (無資料)
%ROWCOUNT=N, %FOUND=FALSE, %NOTFOUND=TRUE  ← 關鍵判斷點
  ↓ CLOSE
%ISOPEN=FALSE, 其他屬性保持最後狀態

隱式游標 (DML):
執行前 → %ROWCOUNT=0, %FOUND=NULL, %NOTFOUND=NULL
  ↓ UPDATE/INSERT/DELETE
%ROWCOUNT=影響列數, %FOUND=(>0), %NOTFOUND=(=0)
  ↓ 下一個 DML/SELECT
屬性被新語句覆蓋

完整實戰範例:顯式游標屬性示範

SET SERVEROUTPUT ON

DECLARE
  -- 靜態游標
  CURSOR emps IS
    SELECT * FROM employees WHERE ROWNUM < 6 ORDER BY employee_id;
  
  l_emp employees%ROWTYPE;
  l_row_num NUMBER := 1;
BEGIN
  -- 開啟游標
  OPEN emps;
  DBMS_OUTPUT.PUT_LINE('OPEN 後 %ISOPEN=' || CASE WHEN emps%ISOPEN THEN 'TRUE' ELSE 'FALSE' END);

  -- 首次 FETCH
  FETCH emps INTO l_emp;
  DBMS_OUTPUT.PUT_LINE('首次 FETCH: %ROWCOUNT=' || emps%ROWCOUNT || 
                       ' %FOUND=' || CASE WHEN emps%FOUND THEN 'TRUE' ELSE 'FALSE' END);

  -- 迴圈處理
  LOOP
    IF emps%FOUND THEN
      DBMS_OUTPUT.PUT_LINE('處理第 ' || l_row_num || ' 筆: ID=' || l_emp.employee_id || 
                           ' 累計=' || emps%ROWCOUNT);
      FETCH emps INTO l_emp;
      l_row_num := l_row_num + 1;
    ELSIF emps%NOTFOUND THEN
      DBMS_OUTPUT.PUT_LINE('無更多資料,結束迴圈');
      EXIT;
    END IF;
  END LOOP;

  -- 關閉前檢查
  IF emps%ISOPEN THEN
    CLOSE emps;
    DBMS_OUTPUT.PUT_LINE('游標已關閉');
  END IF;
END;
/

進階應用模式

模式 1:%ROWCOUNT 進行進度追蹤

DECLARE
  CURSOR c_big IS SELECT * FROM large_table;
  TYPE t_tab IS TABLE OF large_table%ROWTYPE;
  l_tab t_tab;
  l_total NUMBER := 0;
BEGIN
  OPEN c_big;
  LOOP
    FETCH c_big BULK COLLECT INTO l_tab LIMIT 10000;
    EXIT WHEN l_tab.COUNT = 0;
    
    -- 批次處理邏輯
    FORALL i IN 1..l_tab.COUNT
      INSERT INTO target VALUES l_tab(i);
    
    l_total := l_total + l_tab.COUNT;
    
    -- 每 10 萬列記錄進度
    IF MOD(l_total, 100000) = 0 THEN
      DBMS_OUTPUT.PUT_LINE('已處理: ' || l_total || ' 列');
      -- 或寫入日誌表
    END IF;
  END LOOP;
  CLOSE c_big;
  DBMS_OUTPUT.PUT_LINE('總計處理: ' || l_total);
END;
/

模式 2:%NOTFOUND 作為迴圈終止條件(標準模式)

OPEN c_data;
LOOP
  FETCH c_data INTO l_rec;
  EXIT WHEN c_data%NOTFOUND;  -- 最清晰的終止判斷
  process(l_rec);
END LOOP;
CLOSE c_data;

模式 3:%ISOPEN 防禦性關閉(例外處理必備)

DECLARE
  CURSOR c IS SELECT * FROM t;
BEGIN
  OPEN c;
  -- 處理邏輯...
EXCEPTION
  WHEN OTHERS THEN
    IF c%ISOPEN THEN CLOSE c; END IF;  -- 確保資源釋放
    RAISE;
END;

模式 4:隱式游標屬性檢查 DML 結果

BEGIN
  DELETE FROM temp_table WHERE created_date < SYSDATE - 30;
  
  IF SQL%ROWCOUNT = 0 THEN
    DBMS_OUTPUT.PUT_LINE('無資料刪除');
  ELSIF SQL%ROWCOUNT > 10000 THEN
    DBMS_OUTPUT.PUT_LINE('大量刪除: ' || SQL%ROWCOUNT || ' 列,建議分批');
  ELSE
    DBMS_OUTPUT.PUT_LINE('正常刪除: ' || SQL%ROWCOUNT || ' 列');
  END IF;
  
  COMMIT;
EXCEPTION
  WHEN OTHERS THEN
    ROLLBACK;
    RAISE;
END;
/

常見誤區與陷阱

誤區正確認知
%FOUND 在 OPEN 後立即為 TRUEOPEN 後屬性未變,需 FETCH 後才更新
%ROWCOUNT 在 OPEN 後歸零宣告時即為 0,OPEN 不改變
%NOTFOUND 等同於 NOT %FOUND初始皆為 NULL,NULL != TRUE/FALSE,需用 %NOTFOUND 判斷
隱式游標有 %ISOPEN隱式游標 %ISOPEN 永遠 FALSE
FOR rec IN c LOOP 可存取 c%ROWCOUNTFOR 迴圈隱式游標無名稱,無法存取屬性
BULK COLLECT 後 %ROWCOUNT 只加 1%ROWCOUNT 正確累加實際提取列數

除錯技巧:記錄游標狀態

CREATE OR REPLACE PROCEDURE debug_cursor_state(p_cursor_name VARCHAR2, p_cursor IN OUT SYS_REFCURSOR) IS
BEGIN
  DBMS_OUTPUT.PUT_LINE(p_cursor_name || ': %ISOPEN=' || CASE WHEN p_cursor%ISOPEN THEN 'T' ELSE 'F' END ||
                       ' %ROWCOUNT=' || p_cursor%ROWCOUNT);
END;
/
-- 使用
debug_cursor_state('MAIN_CURSOR', c_main);

總結:屬性使用黃金法則

  1. 迴圈終止:永遠用 EXIT WHEN cursor%NOTFOUND
  2. 進度追蹤:用 cursor%ROWCOUNT
  3. 資源管理:例外區塊用 IF cursor%ISOPEN THEN CLOSE cursor
  4. DML 檢查:緊接 DML 後用 SQL%ROWCOUNT/%FOUND
  5. 初始狀態:記住 %FOUND/%NOTFOUND 初始為 NULL,非 TRUE/FALSE
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved