每次執行 DML (INSERT/UPDATE/DELETE) 或 SELECT INTO 時,Oracle 自動打開隱式游標,通過 SQL% 前綴屬性即可獲取執行結果。本文詳細講解四大屬性語義、取值時機、典型應用場景與常見誤區。
| 屬性 | 類型 | 含義 | 取值示例 |
|---|---|---|---|
SQL%FOUND | BOOLEAN | 最近 DML/SELECT INTO 影響或返回 ≥1 行 | UPDATE 影響 3 行 → TRUE |
SQL%NOTFOUND | BOOLEAN | SQL%FOUND 邏輯非 | DELETE 0 行 → TRUE |
SQL%ROWCOUNT | NUMBER | 最近 DML 影響行數 / SELECT INTO 返回行數 (0 或 1) | INSERT 1 行 → 1 |
SQL%ISOPEN | BOOLEAN | 隱式游標始終為 FALSE (執行即自動關閉) | 永遠 FALSE |
SQL%FOUND/ NOTFOUND = NULL,SQL%ROWCOUNT = NULL。SELECT INTO 返回 0 行 → 拋出 NO_DATA_FOUND,屬性仍更新 (ROWCOUNT=0, NOTFOUND=TRUE)。
BEGIN
UPDATE emp SET sal = sal * 1.1 WHERE deptno = 99; -- 不存在的部門
IF SQL%ROWCOUNT = 0 THEN
DBMS_OUTPUT.PUT_LINE('無記錄更新,請檢查條件');
ELSE
DBMS_OUTPUT.PUT_LINE('成功更新 ' || SQL%ROWCOUNT || ' 行');
END IF;
END;
DECLARE
v_cnt NUMBER := 0;
BEGIN
FOR r IN (SELECT * FROM big_table WHERE process_flag = 'N') LOOP
UPDATE big_table SET process_flag = 'Y', process_time = SYSDATE WHERE id = r.id;
v_cnt := v_cnt + SQL%ROWCOUNT;
IF MOD(v_cnt, 1000) = 0 THEN
COMMIT; -- 每 1000 行提交一次
END IF;
END LOOP;
COMMIT;
END;
BEGIN
SELECT sal INTO v_sal FROM emp WHERE empno = 9999;
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- 也可用 SQL%NOTFOUND 判斷,但異常塊更清晰
v_sal := 0;
END;
-- 或無異常寫法 (需確保唯一)
DECLARE
v_cnt NUMBER;
BEGIN
SELECT COUNT(*) INTO v_cnt FROM emp WHERE empno = 9999;
IF v_cnt = 1 THEN
SELECT sal INTO v_sal FROM emp WHERE empno = 9999;
ELSE
v_sal := 0;
END IF;
END;
| 誤區 | 正確理解 |
|---|---|
SQL%ROWCOUNT 可用於 SELECT 多行查詢 | 隱式游標僅支持 SELECT INTO (單行);多行查詢需顯式游標或 BULK COLLECT |
SQL%FOUND 在 IF 中直接用需注意 NULL | 執行前為 NULL,建議先執行 DML 再判斷,或用 SQL%ROWCOUNT > 0 |
| 隱式游標可重用 | 每條 DML/SELECT INTO 都會重置屬性,不可跨語句引用上一條結果 |
SQL%ISOPEN 有實際用途 | 永遠 FALSE,無實際參考價值 |
COMMIT:永久保存變更,釋放鎖。ROLLBACK:撤銷變更,釋放鎖。SAVEPOINT name:設置保存點,支持部分回滾 ROLLBACK TO name。SET TRANSACTION READ ONLY / ISOLATION LEVEL SERIALIZABLE:設置事務特性。隱式游標屬性是 PL/SQL 控制流程的「儀表盤」。牢記 SQL%ROWCOUNT 為核心計數器,SQL%FOUND/NOTFOUND 為布爾判斷,SQL%ISOPEN 無用。在批量 DML、條件邏輯、異常處理中靈活運用,能編寫出健壯、高效的過程代碼。