PL/SQL入門--exception

 13.處理例外

  1.例外分類:預定義例外,非預定義例外,自定義例外三種

  2.例外處理:

  傳遞例外:如果在例外處理部分EXCEPTON沒有捕捉例外,ORACLE會將例外傳遞到調用環境.

  捕捉並處理例外:使用例外處理部分完成

 

  1. exception 
  2.  
  3.   when exception1 [or exception2...] then 
  4.  
  5.   statement1; 
  6.  
  7.   statement2; 
  8.  
  9.   ..... 
  10.  
  11.   when .... 
  12.  
  13.   ... 
  14.  
  15.   when others then    --必須是例外處理部分的最後一條子句 
  16.  
  17.   statement1; 
  18.  
  19.   ... 

  2.處理預定義例外

  常用預定義例外

  2.1access_into_null:ora-06530錯誤.在引用對象屬性之前,必須首先初始化對象,否則觸發例外

  2.2case_not_found:ora-06592.在編寫CASE語句時,如果在WHEN子句中沒有包含必須的條件分支,並且沒有包含ELSE子句,就會觸發

  1. undef no 
  2.  
  3.  declare 
  4.  
  5.    v_sal emp.sal%type; 
  6.  
  7.  begin 
  8.  
  9.   select sal into v_sal from emp where empno=&&no; 
  10.  
  11.   case 
  12.  
  13.     when v_sal<1000 then 
  14.  
  15.       update emp set salsal=sal+100 where empno=&no; 
  16.  
  17.     when v_sal<2000 then 
  18.  
  19.       update emp set salsal=sal+150 where empno=&no; 
  20.  
  21.     when v_sal<3000 then 
  22.  
  23.       update emp set salsal=sal+200 where empno=&no; 
  24.  
  25.   end case; 
  26.  
  27.   exception 
  28.  
  29.     when case_not_found then 
  30.  
  31.     dbms_output.put_line('在CASE語句中缺少與'||v_sal||'相關的條件'); 
  32.  
  33.   end;  

 

  2.3collection_is_null:ora-06531

  在給集合元素(嵌套表和VARRAY類型)賦值前,必須首先初始化集合元素,否則觸發例外

  1. declare 
  2.  
  3.    type ename_table_type is table of emp.ename%type; 
  4.  
  5.    ename_table ename_table_type; 
  6.  
  7.  begin 
  8.  
  9.    select ename into ename_table(2) from emp where empno=&no; 
  10.  
  11.    dbms_output.put_line('僱員名:||ename_table(2); 
  12.  
  13.    exception 
  14.  
  15.      when collection_null then 
  16.  
  17.        dbms_output.put_line('必須使用構造方法初始化集合元素'); 
  18.  
  19.  end; 

  2.4cursor_already_open:ora-06511

  當重新打開已經打開的遊標時,會隱含的觸發例外.已經使用OPEN打開了顯示遊標,並執行FOR循環,就會隱含的觸發該例外

 

  1. declare 
  2.  
  3.    cursor emp_cursor is select ename,sal from emp; 
  4.  
  5.  begin 
  6.  
  7.    open emp_cursor; 
  8.  
  9.    for emp_record in emp_cursor loop 
  10.  
  11.      dbms_output.put_line(emp_record.ename); 
  12.  
  13.    end loop; 
  14.  
  15.    exception 
  16.  
  17.      when cursor_already_open then 
  18.  
  19.      dbms_output.put_line('遊標已打開'); 
  20.  
  21.  end; 

  2.5DUP_VAL_ON_INDEX:ORA-00001

  當在唯一索引所對應的列上鍵入重複值時,觸發例外

  1. begin 
  2.  
  3.    update dept set deptno=&new_no where deptno=&old_no; 
  4.  
  5.    exception 
  6.  
  7.      when dup_val_on_index then 
  8.  
  9.        dbms_output.put_line('在DEPTNO列上不能出現重複值'); 
  10.  
  11.  end; 

  2.6invalid_cursor:ora-01001

  當試圖在不合法的遊標上執行操作時,會隱含的觸發例外.要從未打開的遊標提取數據,或者關閉未打開的遊標,則觸發例外

  1. declare 
  2.  
  3.     cursor emp_cursor is select ename,sal from emp; 
  4.  
  5.     emp_record emp_cursor%rowtype; 
  6.  
  7.   begin 
  8.  
  9.     fetch emp_cursor into emp_record; 
  10.  
  11.     close emp_cursor; 
  12.  
  13.   exception 
  14.  
  15.     when invalid_cursor then 
  16.  
  17.       dbms_output.put_line('請檢查遊標是否已經打開'); 
  18.  
  19.   end; 

  2.7invalid_number:ora-01722

  當內嵌SQL語句不能有效的將字符轉變成數字時,會隱含觸發例外

  1. begin 
  2.  
  3.    update emp set salsal=sal+'1oo'; 
  4.  
  5.  exception 
  6.  
  7.    when invalid_number then 
  8.  
  9.      dbms_output.put_line('輸入的數字值不正確'); 
  10.  
  11.  end; 

  2.8no_date_found:ora-01403

  當執行SELECT INTO 未返回行,或者引用了索引表未初始化的元素時,會隱含觸發例外

  1. declare 
  2.  
  3.     v_sal emp.sal%type; 
  4.  
  5.   begin 
  6.  
  7.     select sal into v_sal from emp where lower(ename)=lower('&name'); 
  8.  
  9.   exception 
  10.  
  11.     when no_data_found then 
  12.  
  13.       dbms_output.put_line('不存在該僱員'); 
  14.  
  15.   end; 

  2.9too_many_rows:ora-01422

  當執行select into 語句時,如果返回超過一行,則會觸發例外

  1. declare 
  2.  
  3.    v_ename emp.ename%type; 
  4.  
  5.  begin 
  6.  
  7.    select ename into v_ename from emp where sal=&sal; 
  8.  
  9.  exception 
  10.  
  11.    when too_many_rows then 
  12.  
  13.      dbms_output.put_line('返回多行'); 
  14.  
  15.  end; 

  2.10zero_divide:ora-01476

  如果使用數字值除0,則會隱含觸發例外

  1. declare 
  2.  
  3.    num1 int:=100
  4.  
  5.    num2 int:=0
  6.  
  7.    num3 number(6,2); 
  8.  
  9.  begin 
  10.  
  11.    num3:=num1/num2; 
  12.  
  13.  exception 
  14.  
  15.    when zero_divide then 
  16.  
  17.      dbms_output.put_line('分母不能爲0'); 
  18.  
  19.  end; 

  2.11subscript_beyond_count:ora-06533

  當使用嵌套表或VARRAY元素時,如果元素下標超出了嵌套表或VARRAY元素的範圍,則回隱含的觸發例外

  1. declare 
  2.  
  3.    type emp_array_type is varray(20) of varchar2(10); 
  4.  
  5.    emp_output.put_line(emp_array(3)); 
  6.  
  7.  begin 
  8.  
  9.    emp_array:=emp_array_type('scott','maray'); 
  10.  
  11.    dbms_output.put_line(emp_array(3)); 
  12.  
  13.  exception 
  14.  
  15.    when subscript_beyond_count then 
  16.  
  17.      dbms_output.put_line('超出下標範圍'); 
  18.  
  19.  end; 

  2.12subscript_outside_limit:ora-06532

  當使用嵌套表或VARRAY元素時,如果元素下標爲負值,則會隱含觸發例外

  1. declare 
  2.  
  3.    type emp_array_type is varray(20) of varray2(10); 
  4.  
  5.    emp_array emp_array_type; 
  6.  
  7.  begin 
  8.  
  9.    emp_array:=emp_array_type('scott','mary'); 
  10.  
  11.    dbms_output.put_line(emp_array(-1); 
  12.  
  13.  exception 
  14.  
  15.    when subscript_outside_limit then 
  16.  
  17.      dbms_output.put_line('嵌套表和VARRAY下標不能爲負值'); 
  18.  
  19.  end; 

  2.13value_error:ora-06502

  如果變量長度不足以容納實際數據,則會隱含的出發例外

  1. declare 
  2.  
  3.    v_ename varchar2(5); 
  4.  
  5.  begin 
  6.  
  7.    select ename into v_ename from emp where empno=&no; 
  8.  
  9.    dbms_output.put_line(v_ename); 
  10.  
  11.  exception 
  12.  
  13.    when value_error then 
  14.  
  15.      dbms_output.put_line('變量尺寸不足'); 
  16.  
  17.  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.處理非預定義例外

  使用預定義例外,只能處理21ORACLE錯誤.

  使用非預定義例外包括三步:

  在定義部分定義例外名,然後在例外和ORACLE錯誤之間建立關聯,最終在例外處理部分捕捉並處理例外.

  當定義ORACLE錯誤和例外之間的關聯關係時,需要使用僞過程EXCEPTION_INIT

  1. declare 
  2.  
  3.    e_integrity exception; 
  4.  
  5.    pragma exception_init(e_integrity,-2291); 
  6.  
  7.  begin 
  8.  
  9.    update emp set deptno=&dno where empno=&eno; 
  10.  
  11.  exception 
  12.  
  13.    when e_integrity then 
  14.  
  15.      dbms_output.put_line('該部門不存在'); 
  16.  
  17.  end;  

  4.處理自定義例外

  自定義例外與ORACLE錯誤沒有任何關聯

  與預定義和非預定義不同,自定義例外必須顯示觸發

  1. declare 
  2.  
  3.     e_integrity exception; 
  4.  
  5.     pragma exception_init(e_integrity,-2291); 
  6.  
  7.     e_no_employee exception; 
  8.  
  9.   begin 
  10.  
  11.     update emp set deptno=&dno where empno=&eno; 
  12.  
  13.     if sql%notfound then 
  14.  
  15.        raise e_no_employee; 
  16.  
  17.     end if; 
  18.  
  19.     exception 
  20.  
  21.       when e_integrity then 
  22.  
  23.         dbms_output.put_line('該部門不存在'); 
  24.  
  25.       when e_no_employee then 
  26.  
  27.         dbms_output.put_line('該僱員不存在'); 
  28.  
  29.   end; 

  5.使用例外函數

  函數SQLCODE用於取得ORACLE錯誤號,SQLERRM則用於取得與之相關的錯誤信息

  通過在存儲過程.函數.包中使用RAISE_APPLICATION_ERROR可以自定義錯誤號和錯誤消息

  5.1SQLCODESQLERRM

  1. undef v_sal 
  2.  
  3.  declare 
  4.  
  5.    v_ename emp.ename%type; 
  6.  
  7.  begin 
  8.  
  9.    select ename into v_ename from emp where sal=&&v_sal; 
  10.  
  11.    dbms_output.put_line('僱員名:'||v_ename); 
  12.  
  13.  exception 
  14.  
  15.    when no_data_found then 
  16.  
  17.      dbms_output.put_line('不存在工資爲:'||&v_sal||'的僱員'); 
  18.  
  19.    when others then 
  20.  
  21.      dbms_output.put_line('錯誤號:'||SQLCODE); 
  22.  
  23.      dbms_output.put_line('錯誤號:'||sqlerrm); 
  24.  
  25.  end; 

  5.2raise_application_error

  用於在PL/SQL應用程序中自定義錯誤消息

  該過程只能在數據庫端的子程序(過程,函數,,觸發器)中使用,不能在匿名快和客戶端的子程序中使用.

  raise_application_error(error_number,message[,[true|false]]);

  error_number:必須在-20000-20999之間的負整數.MESSAGE不能超過2048字節

  TRUE:該錯誤會被放在先前錯誤堆棧中,FALSE:則會替換先前所有錯誤.

  1. create or replace procedure raise_comm(eno number,commission number) 
  2.  
  3.  is 
  4.  
  5.    v_comm emp.comm%type; 
  6.  
  7.  begin 
  8.  
  9.    select comm into v_comm from emp where empno=eno
  10.  
  11.    if v_comm is null then 
  12.  
  13.       raise_application_error(-20001,'該僱員無補助'); 
  14.  
  15.    end if; 
  16.  
  17.  exception 
  18.  
  19.    when no_data_found then 
  20.  
  21.      dbms_output.put_line('該僱員不存在'); 
  22.  
  23.  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命令中進行設置激活或禁止

  1. alter system set plsql_warnings='enable:all'
  2.  
  3.  alter session set plsql_warnings='enable:performance'
  4.  
  5.  alter procedure hello compile plsql_warnings='enable:performance'
  6.  
  7.  alter session set plsql_warnings='disable:all'
  8.  
  9.  alter session set plsql_warnings='enable:severe','disable:performance','error:06002'; 

  當激活或禁止PL/SQL編譯警告時,不僅可以使用ALTER SYSTEM,ALTER SESSION,ALTER PROCEDURE命令,還可使用PL/SQL系統包DBMS_WARNINGS

  1. SQL>call dbms_warning.set_warning_setting_string('enable:all','session'); 

  7.使用PL/SQL編譯警告

  檢測死代碼

  爲了檢測該子程序是否包含死代碼,必須首先激活警告檢查,然後重新編譯子程序,最後使用SHOW ERRORS命令顯示警告錯誤

  1. alter session set plsql_warnings='enable:informational'
  2.  
  3.   alter prodedure dead_code compile; 
  4.  
  5.   show errors 

  檢測引起性能問題的代碼

  編寫PL/SQL子程序時,如果數值與變量的數據類型不符合,ORACLE會隱含的轉換數據類型,但因爲數據類型轉換會影響子程序性能,所以在編寫PL/SQL子程序時應該儘可能避免性能問題.

  1. create or replace procedure update_sal(name varchar2,salary varchar2) 
  2.  
  3.   is 
  4.  
  5.   begin 
  6.  
  7.     upodate emp set sal=salary where ename=name; 
  8.  
  9.   end; 

  爲了檢測該子程序是否會引起性能問題,應首先激活警告檢查,然後重新編譯子程序,最後再使用SHOW ERRORS顯示警告錯誤

  1. alter session set plsql_warnings='enable:performance'
  2.  
  3.  alter procedure update_sal compile; 
  4.  
  5.  show errors 


感謝April-Myhou 侯老師!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章