Oracle提供了三種異常處理方式:
1:預定義異常 用於處理常見的Oracle錯誤
2:非預定義異常 用於處理預定義異常所不能處理的Oracle錯誤
3:自定義異常 用於處理於Oracle錯誤無關的其他情況
語法:
EXCEPTION
WHEN exception_Name THEN --exception_Name為異常的名字
statement1;
WHEN OTHERS THEN
statement1;
一、 處理預定義異常,系統預定的21種類型
命名的系統異常 | 產生原因 |
access_into_null | 未定義對象 |
case_not_found | case中若未包含相應的when,並且沒有設置 |
collection_is_null | 集合元素未初始化 |
curser_already_open | 游標已經打開 |
dup_val_on_index | 唯一索引對應的列上有重復的值 |
invalid_cursor | 在不合法的游標上進行操作 |
invalid_number | 內嵌的 sql 語句不能將字符轉換為數字 |
no_data_found | 使用 select into 未返回行,或應用索引表未初始化的 |
too_many_rows | 執行 select into 時,結果集超過一行 |
zero_divide | 除數為 0 |
subscript_beyond_count | 元素下標超過嵌套表或varray的最大值 |
subscript_outside_limit | 使用嵌套表或 varray 時,將下標指定為負數 |
value_error | 賦值時,變量長度不足以容納實際數據 |
login_denied | pl/sql 應用程序連接到 oracle 數據庫時,提供了不正確的用戶名或密碼 |
not_logged_on | pl/sql 應用程序在沒有連接 oralce 數據庫的情況下訪問數據 |
program_error | pl/sql 內部問題,可能需要重裝數據字典& pl./sql系統包 |
rowtype_mismatch | 主游標變量與 pl/sql 游標變量的返回類型不兼容 |
self_is_null | 使用對象類型時,在 null 對象上調用對象方法 |
storage_error | 運行 pl/sql 時,超出內存空間 |
sys_invalid_id | 無效的 rowid 字符串 |
timeout_on_resource | oracle 在等待資源時超時 |
二、處理非預定義異常
使用非預定義異常包括三步:
1、在定義部分定義異常名,
2、在異常和Oracle錯誤之間建立關聯,
3、在異常處理部分捕捉並處理異常。
當定義Oracle錯誤和異常之間的關聯關系時,需要使用偽過程EXCEPTION_INIT。
1、首先的定義部分定義異常,
2、使用progma exception_init(exception_name,exception_number) 在異常和oracle錯誤之間建立關聯,
這時要求用戶知道可能出現的錯誤號(異常函數sqlcode、sqlerrm和 raise_application_error);
3、最終在異常處理部分捕捉並處理異常。
下面以更新特定雇員的部門號,並處理ORA-02291錯誤為例,說明使用非預定義異常的方法。示例如下:

DECLARE e_integrity EXCEPTION; --1、定義部分 PRAGMA EXCEPTION_INIT (e_integrity, -2291); --2、建立關聯關系 BEGIN UPDATE emp SET deptno= &dno WHERE empno = &eno; EXCEPTION WHEN e_integrity THEN --3、捕捉處理 DBMS_OUTPUT.PUT_LINE(‘該部門不存在’); END;
三、處理自定義異常
預定義異常和非預定義異常都與Oracle錯誤有關,並且當出現Oracle錯誤時會隱含觸發相應異常;
而自定義異常與Oracle錯誤沒有任何關聯,它是由開發人員為特定情況所定義的異常。
當使用自定義異常時,
1、需要在定義部分(DECLARE)定義異常,
2、再執行部分(BEGIN)觸發異常(使用RAISE語句),
3、在異常處理部分(EXCEPTION)捕捉並處理異常。

CREATE TABLE errlog( Errcode NUMBER, Errtext CHAR(40)); CREATE OR REPLACE FUNCTION get_salary(p_deptno NUMBER) RETURN NUMBER AS v_sal NUMBER; BEGIN IF p_deptno IS NULL THEN RAISE_APPLICATION_ERROR(-20991, ’部門代碼為空’); ELSIF p_deptno<0 THEN RAISE_APPLICATION_ERROR(-20992, ’無效的部門代碼’); ELSE SELECT SUM(employees.salary) INTO v_sal FROM employees WHERE employees.department_id=p_deptno; RETURN v_sal; END IF; END; DECLARE V_salary NUMBER(7,2); V_sqlcode NUMBER; V_sqlerr VARCHAR2(512); Null_deptno EXCEPTION; Invalid_deptno EXCEPTION; PRAGMA EXCEPTION_INIT(null_deptno,-20991); PRAGMA EXCEPTION_INIT(invalid_deptno, -20992); BEGIN V_salary :=get_salary(10); DBMS_OUTPUT.PUT_LINE('10號部門工資:' || TO_CHAR(V_salary)); BEGIN V_salary :=get_salary(-10); EXCEPTION WHEN invalid_deptno THEN V_sqlcode :=SQLCODE; V_sqlerr :=SQLERRM; INSERT INTO errlog(errcode, errtext) VALUES(v_sqlcode, v_sqlerr); COMMIT; END inner1; V_salary :=get_salary(20); DBMS_OUTPUT.PUT_LINE('部門號為20的工資為:'||TO_CHAR(V_salary)); BEGIN V_salary :=get_salary(NULL); END inner2; V_salary := get_salary(30); DBMS_OUTPUT.PUT_LINE('部門號為30的工資為:'||TO_CHAR(V_salary)); EXCEPTION WHEN null_deptno THEN V_sqlcode :=SQLCODE; V_sqlerr :=SQLERRM; INSERT INTO errlog(errcode, errtext) VALUES(v_sqlcode, v_sqlerr); COMMIT; WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM); END outer;