程序执行过程中的错误情况是一个例外(异常)。 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;
SQL
下面写一个代码来说明和理解这个概念,这里使用前面章节中创建和使用的CUSTOMERS
表,结构和数据如下 -
下面是一个未找到数据记录时的异常处理 -
SQL> declare
2 c_id customers.id%type := 100;
3 c_name customers.name%type;
4 c_addr customers.address%type;
5 begin
6 select name,address into c_name,c_addr
7 from customers
8 where id=c_id;
9 dbms_output.put_line('姓名:' || c_name);
10 dbms_output.put_line('地址:' || c_addr);
11
12 exception
13 when no_data_found then
14 dbms_output.put_line('没有找到符合条件的客户信息!');
15 when others then
16 dbms_output.put_line('Error!');
17 end;
18 /
没有找到符合条件的客户信息!
PL/SQL procedure successfully completed
Executed in 0 seconds
上面的程序用于显示指定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;
SQL
可以使用上述语法来引发Oracle标准异常或任何用户定义的异常。 在下一节中,我们将举例说明引发用户定义的异常。您可以用类似的方式引发Oracle中标准异常。
用户定义的异常
PL/SQL允许根据程序的需要定义自己的异常。 用户定义的异常必须声明,然后使用RAISE
语句或过程DBMS_STANDARD.RAISE_APPLICATION_ERROR
显式地引发。
声明异常的语法是 -
DECLARE
my-exception EXCEPTION;
示例
以下示例说明了这个概念。这个程序要求输入一个客户ID,当用户输入一个无效的ID时,会引发异常invalid_id
。参考以下示例代码的实现 -
SQL> 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;
/
Enter value for cc_id: -1
old 2: c_id customers.id%type := &cc_id;
new 2: c_id customers.id%type := -1;
编号ID必须要大于0!
PL/SQL procedure successfully completed.
预定义的异常
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 | 当尝试将数字除以零时引发。 |