在本章中,我們將討論和學習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 |
當嘗試將數位除以零時引發。 |