Oracle資料庫之PL/SQL異常處理
Oracle資料庫之PL/SQL異常處理
異常指的是在程式執行過程中發生的異常事件,通常是由硬體問題或者程式設計問題所導致的。
PL/SQL程式設計過程中,即使是寫得最好的程式也可能會遇到錯誤或未預料到的事件。一個健壯的程式都應該能夠正確處理各種異常情況,並儘可能從中恢復。
1. 異常處理
異常處理是用來處理正常執行過程中未預料的事件。PL/SQL程式塊一旦產生異常而沒有指出如何處理時,程式就會自動終止整個程式執行。
PL/SQL程式設計過程中,有三種類型的異常:
1.預定義異常
對這種異常情況的處理,無需在程式中定義,當PL/SQL程式違反Oracle規則或超越系統限制時隱式引發。
2.非預定義異常
其他標準的Oracle錯誤。對這種異常情況的處理,需要使用者在程式中定義,然後由Oracle自動將其引發。
3.使用者定義異常
程式執行過程中,出現程式設計人員認為的非正常情況。對這種異常情況的處理,需要使用者在程式中定義,然後顯式地在程式中將其引發。
異常處理通常放在PL/SQL程式的後部,語法結構為:
EXCEPTION WHEN { exception [ OR exception ]... | OTHERS } THEN statement [ statement ]...
2. 預定義的異常處理
常見預定義異常:
錯誤號 | 異常名稱 | 說明 |
---|---|---|
ORA-00001 | DUP_VAL_ON_INDEX | 重複索引值,違反了唯一性限制,當在唯一索引所對應的列上鍵入重複值時觸發 |
ORA-01001 | INVALID_CURSOR | 試圖使用一個無效的遊標 |
ORA-01012 | NOT_LOGGED_ON | 沒有連線到ORACLE |
ORA-01017 | LOGIN_DENIED | 無效的使用者名稱/口令 |
ORA-01403 | NO_DATA_FOUND | 沒有找到資料時觸發 |
ORA-01422 | TOO_MANY_ROWS | 返回多行 |
ORA-01722 | INVALID_NUMBER | 轉換為數字失敗時觸發 |
ORA-06511 | CURSOR_ALREADY_OPEN | 試圖開啟一個已處於開啟狀態的遊標 |
ORA-06592 | CASE_NOT_FOUND | 當case條件都不滿足時觸發 |
更多預定義異常見:
對預定義異常的處理,只需在PL/SQL塊的異常處理部分,直接引用相應的異常情況名,並對其完成相應的異常錯誤處理即可。
示例1:
DECLARE stock_price NUMBER := 9.73; net_earnings NUMBER := 0; pe_ratio NUMBER; BEGIN pe_ratio := stock_price / net_earnings; DBMS_OUTPUT.PUT_LINE('運算結果 = ' || pe_ratio); EXCEPTION WHEN ZERO_DIVIDE THEN DBMS_OUTPUT.PUT_LINE('/ by zero'); pe_ratio := NULL; END;
執行結果:
/ by zero
為避免除0異常,可以採用如下示例2方式解決:
示例2:
DECLARE stock_price NUMBER := 9.73; net_earnings NUMBER := 0; pe_ratio NUMBER; BEGIN pe_ratio := CASE net_earnings WHEN 0 THEN NULL ELSE stock_price / net_earnings END; END;
示例3:
DECLARE default_number NUMBER := 0; BEGIN INSERT INTO t VALUES(TO_NUMBER('100.00', '9G999')); EXCEPTION WHEN INVALID_NUMBER THEN DBMS_OUTPUT.PUT_LINE('使用預設值替換非法數字'); INSERT INTO t VALUES(default_number); END;
執行結果:
使用預設值替換非法數字
3. 非預定義的異常處理
非預定義異常有錯誤號沒有名字,處理的辦法是:自己定義一個名字,繫結到錯誤號,捕獲錯誤名。處理這類異常,首先必須對非預定義的Oracle異常進行定義。
如:
myexcp EXCEPTION;
然後使用EXCEPTION_INIT語句與標準的ORACLE錯誤聯絡起來,如:
PRAGMA EXCEPTION_INIT(myexcp,-02292);
說明:ORA-02292是違反完整性約束的錯誤程式碼。
示例:
DECLARE myexcp EXCEPTION; PRAGMA EXCEPTION_INIT(myexcp,-02292); dno scott.emp.deptno%TYPE; BEGIN dno := &dept_no; DELETE FROM scott.dept WHERE deptno=dno; EXCEPTION WHEN myexcp THEN DELETE FROM scott.emp WHERE deptno=dno; DELETE FROM scott.dept WHERE deptno=dno; END;
4. 使用者定義異常處理
我們可以在任何PL/SQL匿名塊,子程式或包的宣告部分宣告自己的異常。使用者定義的異常是通過使用RAISE語句顯式觸發的。
一般使用者定義異常的處理流程為:定義異常->丟擲異常->捕獲及處理異常。
示例:
DECLARE invalidCATEGORY EXCEPTION; -- 定義異常 category VARCHAR2(10); BEGIN category := '&Category'; IF category NOT IN ('附件','頂蓋','備件') THEN RAISE invalidCATEGORY; -- 丟擲異常 ELSE DBMS_OUTPUT.PUT_LINE('您輸入的類別是'|| category); END IF; EXCEPTION WHEN invalidCATEGORY THEN -- 捕獲及處理異常 DBMS_OUTPUT.PUT_LINE('無法識別該類別'); END;
我們可以呼叫RAISE_APPLICATION_ERROR過程引發並傳播應用程式異常,這為應用程式提供了一種與ORACLE互動的方法。
RAISE_APPLICATION_ERROR過程可用於建立使用者定義的錯誤資訊,可以在可執行部分和異常處理部分使用,錯誤編號必須介於–20000 和–20999之間,錯誤訊息的長度可長達2048個位元組。
RAISE_APPLICATION_ERROR過程語法:
RAISE_APPLICATION_ERROR (error_code, message[, {TRUE | FALSE}]);
如果指定TRUE,PL/SQL把ERROR_CODE上的錯誤資訊新增到堆疊的頂部。指定FALSE,PL/SQL替換ERROR_CODE錯誤堆疊,預設值為FALSE。
示例1:
DECLARE empno employees.employee_id%TYPE; no_such_row EXCEPTION; BEGIN empno := &empno; UPDATE employees SET salary = salary+100 WHERE id = empno; IF SQL%NOTFOUND THEN RAISE no_such_row; END IF; EXCEPTION WHEN no_such_row THEN RAISE_APPLICATION_ERROR(-20001, '沒有待修改的行'); END;
示例2:
BEGIN UPDATE emp SET deptno=80 WHERE empno=1111; IF SQL%NOTFOUND THEN RAISE_APPLICATION_ERROR(-20001,'該僱員不存在!'); END IF; EXCEPTION WHEN OTHERS THEN dbms_output.put_line(SQLCODE||'-->'||SQLERRM); END;
SQLCODE用於取得Oracle錯誤號。
SQLERRM則用於取得與之相關的錯誤訊息。