13.處理例外
1.例外分類:預定義例外,非預定義例外,自定義例外三種
2.例外處理:
傳遞例外:如果在例外處理部分EXCEPTON沒有捕捉例外,ORACLE會將例外傳遞到調用環境.
捕捉並處理例外:使用例外處理部分完成
- exception
- when exception1 [or exception2...] then
- statement1;
- statement2;
- .....
- when ....
- ...
- when others then --必須是例外處理部分的最後一條子句
- statement1;
- ...
2.處理預定義例外
常用預定義例外
2.1access_into_null:ora-06530錯誤.在引用對象屬性之前,必須首先初始化對象,否則觸發例外
2.2case_not_found:ora-06592.在編寫CASE語句時,如果在WHEN子句中沒有包含必須的條件分支,並且沒有包含ELSE子句,就會觸發
- undef no
- declare
- v_sal emp.sal%type;
- begin
- select sal into v_sal from emp where empno=&&no;
- case
- when v_sal<1000 then
- update emp set salsal=sal+100 where empno=&no;
- when v_sal<2000 then
- update emp set salsal=sal+150 where empno=&no;
- when v_sal<3000 then
- update emp set salsal=sal+200 where empno=&no;
- end case;
- exception
- when case_not_found then
- dbms_output.put_line('在CASE語句中缺少與'||v_sal||'相關的條件');
- end;
2.3collection_is_null:ora-06531
在給集合元素(嵌套表和VARRAY類型)賦值前,必須首先初始化集合元素,否則觸發例外
- declare
- type ename_table_type is table of emp.ename%type;
- ename_table ename_table_type;
- begin
- select ename into ename_table(2) from emp where empno=&no;
- dbms_output.put_line('僱員名:||ename_table(2);
- exception
- when collection_null then
- dbms_output.put_line('必須使用構造方法初始化集合元素');
- end;
2.4cursor_already_open:ora-06511
當重新打開已經打開的遊標時,會隱含的觸發例外.已經使用OPEN打開了顯示遊標,並執行FOR循環,就會隱含的觸發該例外
- declare
- cursor emp_cursor is select ename,sal from emp;
- begin
- open emp_cursor;
- for emp_record in emp_cursor loop
- dbms_output.put_line(emp_record.ename);
- end loop;
- exception
- when cursor_already_open then
- dbms_output.put_line('遊標已打開');
- end;
2.5DUP_VAL_ON_INDEX:ORA-00001
當在唯一索引所對應的列上鍵入重複值時,觸發例外
- begin
- update dept set deptno=&new_no where deptno=&old_no;
- exception
- when dup_val_on_index then
- dbms_output.put_line('在DEPTNO列上不能出現重複值');
- end;
2.6invalid_cursor:ora-01001
當試圖在不合法的遊標上執行操作時,會隱含的觸發例外.要從未打開的遊標提取數據,或者關閉未打開的遊標,則觸發例外
- declare
- cursor emp_cursor is select ename,sal from emp;
- emp_record emp_cursor%rowtype;
- begin
- fetch emp_cursor into emp_record;
- close emp_cursor;
- exception
- when invalid_cursor then
- dbms_output.put_line('請檢查遊標是否已經打開');
- end;
2.7invalid_number:ora-01722
當內嵌SQL語句不能有效的將字符轉變成數字時,會隱含觸發例外
- begin
- update emp set salsal=sal+'1oo';
- exception
- when invalid_number then
- dbms_output.put_line('輸入的數字值不正確');
- end;
2.8no_date_found:ora-01403
當執行SELECT INTO 未返回行,或者引用了索引表未初始化的元素時,會隱含觸發例外
- declare
- v_sal emp.sal%type;
- begin
- select sal into v_sal from emp where lower(ename)=lower('&name');
- exception
- when no_data_found then
- dbms_output.put_line('不存在該僱員');
- end;
2.9too_many_rows:ora-01422
當執行select into 語句時,如果返回超過一行,則會觸發例外
- declare
- v_ename emp.ename%type;
- begin
- select ename into v_ename from emp where sal=&sal;
- exception
- when too_many_rows then
- dbms_output.put_line('返回多行');
- end;
2.10zero_divide:ora-01476
如果使用數字值除0,則會隱含觸發例外
- declare
- num1 int:=100;
- num2 int:=0;
- num3 number(6,2);
- begin
- num3:=num1/num2;
- exception
- when zero_divide then
- dbms_output.put_line('分母不能爲0');
- end;
2.11subscript_beyond_count:ora-06533
當使用嵌套表或VARRAY元素時,如果元素下標超出了嵌套表或VARRAY元素的範圍,則回隱含的觸發例外
- declare
- type emp_array_type is varray(20) of varchar2(10);
- emp_output.put_line(emp_array(3));
- begin
- emp_array:=emp_array_type('scott','maray');
- dbms_output.put_line(emp_array(3));
- exception
- when subscript_beyond_count then
- dbms_output.put_line('超出下標範圍');
- end;
2.12subscript_outside_limit:ora-06532
當使用嵌套表或VARRAY元素時,如果元素下標爲負值,則會隱含觸發例外
- declare
- type emp_array_type is varray(20) of varray2(10);
- emp_array emp_array_type;
- begin
- emp_array:=emp_array_type('scott','mary');
- dbms_output.put_line(emp_array(-1);
- exception
- when subscript_outside_limit then
- dbms_output.put_line('嵌套表和VARRAY下標不能爲負值');
- end;
2.13value_error:ora-06502
如果變量長度不足以容納實際數據,則會隱含的出發例外
- declare
- v_ename varchar2(5);
- begin
- select ename into v_ename from emp where empno=&no;
- dbms_output.put_line(v_ename);
- exception
- when value_error then
- dbms_output.put_line('變量尺寸不足');
- end;
2.14其他預定義例外
login_denied:ora-01017連接數據庫時,提供了不正確的用戶名和口令
not_logged_on:ora-01012沒有連接到數據庫
program_error:ora-06501存在PL/SQL內部問題,可能需要重新安裝數據字典和PL/SQL系統包
rowtype_mismatch:ora-06504宿主遊標變量和PL/SQL遊標變量的返回類型不兼容
self_is_null:ora-30625使用對象類型時,如果在NULL實例上調用成員方法,則會隱含觸發例外
storage_error:ora-06500如果超出內存或者內存被損壞
sys_invalid_rowid:ora-01410當字符串轉變爲ROWID時,必須使用有效的字符串,否則觸發例外
timeout_on_resource:ora-00051ORACLE在等待資源時出現超時錯誤
3.處理非預定義例外
使用預定義例外,只能處理21個ORACLE錯誤.
使用非預定義例外包括三步:
在定義部分定義例外名,然後在例外和ORACLE錯誤之間建立關聯,最終在例外處理部分捕捉並處理例外.
當定義ORACLE錯誤和例外之間的關聯關係時,需要使用僞過程EXCEPTION_INIT
- declare
- e_integrity exception;
- pragma exception_init(e_integrity,-2291);
- begin
- update emp set deptno=&dno where empno=&eno;
- exception
- when e_integrity then
- dbms_output.put_line('該部門不存在');
- end;
4.處理自定義例外
自定義例外與ORACLE錯誤沒有任何關聯
與預定義和非預定義不同,自定義例外必須顯示觸發
- declare
- e_integrity exception;
- pragma exception_init(e_integrity,-2291);
- e_no_employee exception;
- begin
- update emp set deptno=&dno where empno=&eno;
- if sql%notfound then
- raise e_no_employee;
- end if;
- exception
- when e_integrity then
- dbms_output.put_line('該部門不存在');
- when e_no_employee then
- dbms_output.put_line('該僱員不存在');
- end;
5.使用例外函數
函數SQLCODE用於取得ORACLE錯誤號,而SQLERRM則用於取得與之相關的錯誤信息
通過在存儲過程.函數.包中使用RAISE_APPLICATION_ERROR可以自定義錯誤號和錯誤消息
5.1SQLCODE和SQLERRM
- undef v_sal
- declare
- v_ename emp.ename%type;
- begin
- select ename into v_ename from emp where sal=&&v_sal;
- dbms_output.put_line('僱員名:'||v_ename);
- exception
- when no_data_found then
- dbms_output.put_line('不存在工資爲:'||&v_sal||'的僱員');
- when others then
- dbms_output.put_line('錯誤號:'||SQLCODE);
- dbms_output.put_line('錯誤號:'||sqlerrm);
- end;
5.2raise_application_error
用於在PL/SQL應用程序中自定義錯誤消息
該過程只能在數據庫端的子程序(過程,函數,包,觸發器)中使用,不能在匿名快和客戶端的子程序中使用.
raise_application_error(error_number,message[,[true|false]]);
error_number:必須在-20000和-20999之間的負整數.MESSAGE不能超過2048字節
TRUE:該錯誤會被放在先前錯誤堆棧中,FALSE:則會替換先前所有錯誤.
- create or replace procedure raise_comm(eno number,commission number)
- is
- v_comm emp.comm%type;
- begin
- select comm into v_comm from emp where empno=eno;
- if v_comm is null then
- raise_application_error(-20001,'該僱員無補助');
- end if;
- exception
- when no_data_found then
- dbms_output.put_line('該僱員不存在');
- end;
6.pl/sql編譯警告
6.1PL/SQL警告分類:
severe:該警告用於檢查可能出現的不可預料結果或錯誤結果,例如參數的別名問題
performance:用於檢查可能出現的不可預料結果或錯誤結果,例如參數的別名問題
inforamational:用於檢查子程序中的死代碼
all:該關鍵字用於檢查所有警告(severe,perforamce,informational)
6.2控制PL/SQL警告消息
爲了使數據庫在編譯PL/SQL子程序時發出警告消息,需設置初始化參數PLSQL_WARNINGS.
初始化PLSQL_WARNINGS不僅可在系統級或會話級設置,也可在ALTER PROCEDURE命令中進行設置激活或禁止
- alter system set plsql_warnings='enable:all';
- alter session set plsql_warnings='enable:performance';
- alter procedure hello compile plsql_warnings='enable:performance';
- alter session set plsql_warnings='disable:all';
- alter session set plsql_warnings='enable:severe','disable:performance','error:06002';
當激活或禁止PL/SQL編譯警告時,不僅可以使用ALTER SYSTEM,ALTER SESSION,ALTER PROCEDURE命令,還可使用PL/SQL系統包DBMS_WARNINGS
- SQL>call dbms_warning.set_warning_setting_string('enable:all','session');
7.使用PL/SQL編譯警告
檢測死代碼
爲了檢測該子程序是否包含死代碼,必須首先激活警告檢查,然後重新編譯子程序,最後使用SHOW ERRORS命令顯示警告錯誤
- alter session set plsql_warnings='enable:informational';
- alter prodedure dead_code compile;
- show errors
檢測引起性能問題的代碼
編寫PL/SQL子程序時,如果數值與變量的數據類型不符合,ORACLE會隱含的轉換數據類型,但因爲數據類型轉換會影響子程序性能,所以在編寫PL/SQL子程序時應該儘可能避免性能問題.
- create or replace procedure update_sal(name varchar2,salary varchar2)
- is
- begin
- upodate emp set sal=salary where ename=name;
- end;
爲了檢測該子程序是否會引起性能問題,應首先激活警告檢查,然後重新編譯子程序,最後再使用SHOW ERRORS顯示警告錯誤
- alter session set plsql_warnings='enable:performance';
- alter procedure update_sal compile;
- show errors
感謝April-Myhou 侯老師!