PL/SQL例外處理


在本章中,我們將討論和學習PL/SQL中的異常。 程式執行過程中的錯誤情況是一個例外(異常)。 PL/SQL支援程式員在程式中使用EXCEPTION塊捕獲這些發生錯誤的條件,並針對錯誤情況採取適當的措施。PL/SQL中有兩種異常 -

  • 系統定義的異常
  • 使用者定義的異常

例外處理的語法

例外處理的一般語法如下。在這裡,可以列舉儘可能多的異常並且指定處理方式。預設的異常將使用WHEN...THEN處理,如下語法所示 -

DECLARE 
   <declarations section> 
BEGIN 
   <executable command(s)> 
EXCEPTION 
   <exception handling goes here > 
   WHEN exception1 THEN  
      exception1-handling-statements  
   WHEN exception2  THEN  
      exception2-handling-statements  
   WHEN exception3 THEN  
      exception3-handling-statements 
   ........ 
   WHEN others THEN 
      exception3-handling-statements 
END;

範例

下面寫一個程式碼來說明和理解這個概念,這裡使用前面章節中建立和使用的CUSTOMERS表,結構和資料如下 -

CREATE TABLE CUSTOMERS( 
   ID   INT NOT NULL, 
   NAME VARCHAR (20) NOT NULL, 
   AGE INT NOT NULL, 
   ADDRESS CHAR (25), 
   SALARY   DECIMAL (18, 2),        
   PRIMARY KEY (ID) 
);
-- 向CUSTOMERS表中插入一些資料記錄 
INSERT INTO CUSTOMERS (ID,NAME,AGE,ADDRESS,SALARY) 
VALUES (1, 'Ramesh', 32, 'Ahmedabad', 2000.00 );  

INSERT INTO CUSTOMERS (ID,NAME,AGE,ADDRESS,SALARY) 
VALUES (2, 'Khilan', 25, 'Delhi', 1500.00 );  

INSERT INTO CUSTOMERS (ID,NAME,AGE,ADDRESS,SALARY) 
VALUES (3, 'kaushik', 23, 'Kota', 2000.00 );

INSERT INTO CUSTOMERS (ID,NAME,AGE,ADDRESS,SALARY) 
VALUES (4, 'Chaitali', 25, 'Mumbai', 6500.00 ); 

INSERT INTO CUSTOMERS (ID,NAME,AGE,ADDRESS,SALARY) 
VALUES (5, 'Hardik', 27, 'Bhopal', 8500.00 );  

INSERT INTO CUSTOMERS (ID,NAME,AGE,ADDRESS,SALARY) 
VALUES (6, 'Komal', 22, 'MP', 4500.00 );

下面是一個未找到資料記錄時的例外處理 -

SET SERVEROUTPUT ON SIZE 99999;
DECLARE 
   c_id customers.id%type := 100; 
   c_name  customerS.name%type; 
   c_addr customers.address%type; 
BEGIN 
   SELECT  name, address INTO  c_name, c_addr 
   FROM customers 
   WHERE id = c_id;  
   DBMS_OUTPUT.PUT_LINE ('姓名: '||  c_name); 
   DBMS_OUTPUT.PUT_LINE ('地址: ' || c_addr); 

EXCEPTION 
   WHEN no_data_found THEN 
      dbms_output.put_line('沒有找到符合條件的客戶資訊!'); 
   WHEN others THEN 
      dbms_output.put_line('Error!'); 
END; 
/

執行上面範例程式碼,得到以下結果 -

上面的程式用於顯示指定ID的客戶的名字和地址。但是由於資料庫customers表中並沒有ID值為100的客戶,因此程式引發異常,並在EXCEPTION塊中捕獲的執行時異常NO_DATA_FOUND,因此最後列印了資訊:‘沒有找到符合條件的客戶資訊!’

引發異常

只要有內部資料庫錯誤,資料庫伺服器就會自動產生(引發)異常,但程式員可以使用命令RAISE明確地引發異常。以下是引發異常的簡單語法 -

DECLARE 
   exception_name EXCEPTION; 
BEGIN 
   IF condition THEN 
      RAISE exception_name; 
   END IF; 
EXCEPTION 
   WHEN exception_name THEN 
   statement; 
END;

可以使用上述語法來引發Oracle標準異常或任何使用者定義的異常。 在下一節中,我們將舉例說明引發使用者定義的異常。您可以用類似的方式引發Oracle中標準異常。

使用者定義的異常

PL/SQL允許根據程式的需要定義自己的異常。 使用者定義的異常必須宣告,然後使用RAISE語句或過程DBMS_STANDARD.RAISE_APPLICATION_ERROR顯式地引發。

宣告異常的語法是 -

DECLARE 
   my-exception EXCEPTION;

範例

以下範例說明了這個概念。這個程式要求輸入一個客戶ID,當使用者輸入一個無效的ID時,會引發異常invalid_id。參考以下範例程式碼的實現 -

SET SERVEROUTPUT ON SIZE 9999;
DECLARE 
   c_id customers.id%type := &cc_id; 
   c_name  customerS.name%type; 
   c_addr customers.address%type;  
   -- user defined exception 
   ex_invalid_id  EXCEPTION; 
BEGIN 
   IF c_id <= 0 THEN 
      RAISE ex_invalid_id; 
   ELSE 
      SELECT  name, address INTO  c_name, c_addr 
      FROM customers 
      WHERE id = c_id;
      DBMS_OUTPUT.PUT_LINE ('姓名: '||  c_name);  
      DBMS_OUTPUT.PUT_LINE ('地址: ' || c_addr); 
   END IF; 

EXCEPTION 
   WHEN ex_invalid_id THEN 
      dbms_output.put_line('編號ID必須要大於0!'); 
   WHEN no_data_found THEN 
      dbms_output.put_line('未找到指定ID的客戶資訊!'); 
   WHEN others THEN 
      dbms_output.put_line('Error!');  
END; 
/

執行上面範例程式碼,得到以下結果 -

輸入 cc_id 的值:  -1
原值    2:    c_id customers.id%type := &cc_id;
新值    2:    c_id customers.id%type := -1;
編號ID必須要大於0!

PL/SQL 過程已成功完成。

預定義的異常

PL/SQL提供了許多預定義的異常,這些異常在程式違反任何資料庫規則時執行。 例如,當SELECT INTO語句不返回任何行時,會引發預定義的異常NO_DATA_FOUND。下表列出了一些重要的預定義異常情況 -

異常 Oracle錯誤程式碼 SQLCODE 描述
ACCESS_INTO_NULL 06530 -6530 當一個空物件被自動分配一個值時會引發它。
CASE_NOT_FOUND 06592 -6592 當沒有選擇CASE語句的WHEN子句中的任何選項時,會引發這個錯誤,並且沒有ELSE子句。
COLLECTION_IS_NULL 06531 -6531 當程式嘗試將EXISTS以外的集合方法應用於未初始化的巢狀表或varray時,或程式嘗試將值分配給未初始化的巢狀表或varray的元素時,會引發此問題。
DUP_VAL_ON_INDEX 00001 -1 當嘗試將重複值儲存在具有唯一索引的列中時引發此錯誤。
INVALID_CURSOR 01001 -1001 當嘗試進行不允許的游標操作(例如關閉未開啟的游標)時會引發此錯誤。
INVALID_NUMBER 01722 -1722 當字串轉換為數位時失敗,因為字串不代表有效的數位。
LOGIN_DENIED 01017 -1017 當程式嘗試使用無效的使用者名或密碼登入到資料庫時引發。
NO_DATA_FOUND 01403 +100 SELECT INTO語句不返回任何行時會引發它。
NOT_LOGGED_ON 01012 -1012 當資料庫呼叫沒有連線到資料庫時引發。
PROGRAM_ERROR 06501 -6501 當PL/SQL遇到內部問題時會引發。
ROWTYPE_MISMATCH 06504 -6504 當游標在具有不相容資料型別的變數中獲取值時引發。
SELF_IS_NULL 30625 -30625 當呼叫成員方法時引發,但物件型別的範例未初始化。
STORAGE_ERROR 06500 -6500 當PL/SQL用盡記憶體或記憶體已損壞時引發。
TOO_MANY_ROWS 01422 -1422 SELECT INTO語句返回多行時引發。
VALUE_ERROR 06502 -6502 當發生算術,轉換,截斷或者sizeconstraint錯誤時引發。
ZERO_DIVIDE 01476 1476 當嘗試將數位除以零時引發。