Oracle Developer (PL/SQL) 異常處理機制完善,能將錯誤邏輯與業務邏輯分離,大幅提升程式碼可讀性與維護性。本文系統整理異常處理核心觀念與實戰技巧。
無異常時需逐行檢查錯誤,程式碼混雜難讀:
BEGIN
SELECT ...; -- check NO_DATA_FOUND
SELECT ...; -- check NO_DATA_FOUND
SELECT ...; -- check NO_DATA_FOUND
END;
引入異常處理後:
BEGIN
SELECT ...;
SELECT ...;
SELECT ...;
EXCEPTION
WHEN NO_DATA_FOUND THEN -- 統一捕獲所有查無資料
...
END;
優點: 錯誤處理集中、業務邏輯清晰、可讀性強、易維護。
| 類別 | 來源 | 處理方式 |
|---|---|---|
| 內部異常 | Oracle 執行期錯誤 (除零、記憶體不足) 或違反規則 | 隱式拋出,可用預定義名稱或 PRAGMA EXCEPTION_INIT 關聯錯誤碼 |
| 使用者自定義異常 | 開發者依業務邏輯定義 | 宣告區 EXCEPTION 關鍵字,RAISE 顯式拋出 |
| 異常名稱 | Oracle Error | SQLCODE | 觸發情境 |
|---|---|---|---|
| NO_DATA_FOUND | ORA-01403 | +100 | SELECT INTO 無資料 |
| TOO_MANY_ROWS | ORA-01422 | -1422 | SELECT INTO 多筆資料 |
| DUP_VAL_ON_INDEX | ORA-00001 | -1 | 唯一索引鍵重複 |
| VALUE_ERROR | ORA-06502 | -6502 | 字元轉換/截斷/長度不足 |
| STORAGE_ERROR | ORA-06500 | -6500 | 記憶體不足 |
| ZERO_DIVIDE | ORA-01476 | -1476 | 除數為零 |
| CASE_NOT_FOUND | ORA-06592 | -6592 | CASE 無匹配且無 ELSE |
| CURSOR_ALREADY_OPEN | ORA-06511 | -6511 | 重複開啟游標 |
| TIMEOUT_ON_RESOURCE | ORA-00051 | -51 | 資源等待逾時 |
未預定義的內部異常可用 OTHERS 捕獲,或 PRAGMA EXCEPTION_INIT(my_exc, -error_code) 關聯自訂名稱。
RAISE exception_name; 可拋出自定義或預定義異常。RAISE_APPLICATION_ERROR(-20001, 'Custom msg', TRUE/FALSE);
TRUE 疊加錯誤堆疊,FALSE (預設) 覆蓋。EXCEPTION
WHEN exception_name THEN
-- 處理碼
WHEN another_exception THEN
-- 處理碼
WHEN OTHERS THEN
-- 預設處理器 (必須置最後)
err_code := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 100);
INSERT INTO error_log VALUES (err_code, err_msg);
END;
處理完成後控制權返回上層區塊緊接著的陳述式,不會回到拋出點。
-- 內層無處理器,外層捕獲
BEGIN
BEGIN
RAISE my_exc;
EXCEPTION
WHEN OTHERS THEN NULL; -- 若這裡不處理,外層 WHEN OTHERS 會收到
END;
EXCEPTION
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('外層捕獲');
END;
-- 異常區再拋出
BEGIN
BEGIN
RAISE exc_a;
EXCEPTION
WHEN exc_a THEN RAISE exc_b; -- 立即傳播給外層
WHEN exc_b THEN NULL; -- 永遠不會執行
END;
EXCEPTION
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('外層捕獲 exc_b');
END;
SQLCODE:回傳 Oracle 錯誤碼 (負數),NO_DATA_FOUND 為 +100,自定義異常為 +1。SQLERRM:回傳完整錯誤訊息 (含錯誤碼),長度 ≤ 512 bytes。自定義異常回傳 User-Defined Exception。SQLCODE=0、SQLERRM='ORA-0000: normal, successful completion'。最外層區塊建議保留 WHEN OTHERS 記錄錯誤日誌,確保無錯誤漏捕。
ACCESS_INTO_NULL ORA-06530 -6530
CASE_NOT_FOUND ORA-06592 -6592
COLLECTION_IS_NULL ORA-06531 -6531
CURSOR_ALREADY_OPEN ORA-06511 -6511
DUP_VAL_ON_INDEX ORA-00001 -1
INVALID_CURSOR ORA-01001 -1001
INVALID_NUMBER ORA-01722 -1722
LOGIN_DENIED ORA-01017 -1017
NO_DATA_FOUND ORA-01403 +100
NOT_LOGGED_ON ORA-01012 -1012
PROGRAM_ERROR ORA-06501 -6501
ROWTYPE_MISMATCH ORA-06504 -6504
SELF_IS_NULL ORA-30625 -30625
STORAGE_ERROR ORA-06500 -6500
SUBSCRIPT_BEYOND_COUNT ORA-06533 -6533
SUBSCRIPT_OUTSIDE_LIMIT ORA-06532 -6532
SYS_INVALID_ROWID ORA-01410 -1410
TIMEOUT_ON_RESOURCE ORA-00051 -51
TOO_MANY_ROWS ORA-01422 -1422
VALUE_ERROR ORA-06502 -6502
ZERO_DIVIDE ORA-01476 -1476