今天一个朋友在MSN上问一个问题。他在PL/SQL代码的时候,需要捕获主键插入重复异常。他说,有没有类似于“NO_DATA_FOUND”类型的常量信息来指代这种错误,然后好进行错误处理。
这个问题涉及到Oracle PL/SQL代码的错误处理机制,以及预定义的错误信息,这里简单说一下。
Oracle的PL/SQL语言作为一种独立语言出现,极大弥补了纯SQL语句上的缺陷和不足。加入过程化因素,使得在数据库端实现复杂业务逻辑的目标得以实现。作为一种独立编程语言,错误异常处理(Error/Exception Handle)是一个不可或缺的部分。
异常Exception发生的原因有很多,比如设计缺陷、代码错误、业务数据缺陷和软硬件故障等等。在开发阶段预想到所有可能发生的异常是不可能的,但是作为开发人员,我们是可以捕获和处理异常的。正确捕获和处理异常非常重要,特别是进行一些关键的DML操作,要保证数据和业务的完整性。
Oracle中的Exception有两种,一种是内部定义的(也成为运行时异常)、另一种是用户定义异常。内部异常通过编号进行标志,例如ORA_XXXX。内部错误是由Oracle内部定义,并且由Oracle自己去检测激发。一些常见的内部异常,是有自己的预定义名称的。如我们常见的TOO_MANY_ROWS、ZERO_DIVIDE等。朋友的意思也就是找到匹配“主键重复”错误的预定义名称。
对异常的处理,首先谈到的是异常的检测。在目前流行的语言(如Java、C#)中,都是采用类似“try…catch…finally”的结构。在一段代码中检测异常,当发生的时候,通过层层检验捕捉。最后使用finally进行资源回收。
Oracle的pl/sql同样采用了这种类似的结构。是使用一个begin---end块包裹,如下:
set serveroutput on size 10000;
declare
n_totalsal number :=1000;
n_number number :=0;
n_price number;
begin
n_price := n_totalsal/n_number;
exception
when too_many_rows then
dbms_output.put_line('Too Many Data Found !');
when zero_divide then
dbms_output.put_line('zero_divide');
when others then
dbms_output.put_line('Others');
end;
/
这段代码,最终生成异常,并且被zero_divide所拦截。匿名块返回结果为:
SQL>
zero_divide
PL/SQL procedure successfully completed
在Oracle中,同样存在一些像too_many_rows这种预定义的错误信息。下面从参考文献中找出归纳。
|
异常名称 |
ORA ERROR |
SQLCODE |
含义和抛出点 |
|
ACCESS_INTO_NULL |
06530 |
-6530 |
当程序给一个未初始化对象的属性赋值时候,抛出; |
|
CASE_NOT_FOUND |
06592 |
-6592 |
使用Case语句的时候,没有使用else字句,并且when的情况不能覆盖; |
|
COLLECTION_IS_NULL |
06531 |
-6531 |
当调用一个未初始化数组或者集合对象的非Exists方法,或者对一个为未初始化数组集合赋值; |
|
CURSOR_ALREADY_OPEN |
06511 |
-6511 |
程序试图打开一个已经打开的cursor。打开游标只能是针对一个关闭的游标进行; |
|
DUP_VAL_ON_INDEX |
00001 |
-1 |
违反索引唯一约束; |
|
INVALID_CURSOR |
01001 |
-1001 |
对游标进行非法操作,比如关闭一个处在非打开状态的游标; |
|
INVALID_NUMBER |
01722 |
-1722 |
数字类型转换错误; |
|
LOGIN_DENIED |
01017 |
|
非法用户名密码登录; |
|
NO_DATA_FOUND |
01403 |
+100 |
使用select into的时候,如果没有返回值; |
|
NOT_LOGGED_ON |
01012 |
-1012 |
在没有登录的情况下,调用数据库操作命令; |
|
PROGRAM_ERROR |
06501 |
-6501 |
PL/SQL发生了内部错误; |
|
ROWTYPE_MISMATCH |
06504 |
-6504 |
本地游标和PL/SQL游标返回类型不匹配; |
|
SELF_IS_NULL |
30625 |
-30625 |
试图调用一个没有初始化的对象的方法成员,因为关键字SELF表示的是对象的自生(是内建参数),在调用时候总是第一个传递给方法成员。 |
|
STORAGE_ERROR |
06500 |
-6500 |
PL/SQL代码超出内存或者内存崩溃; |
|
SUBSCRIPT_BEYOND_COUNT |
06533 |
-6533 |
访问数组、集合的时候,地址index超过下标界限(过上界); |
|
SUBSCRIPT_OUTSIDE_LIMIT |
06532 |
-6532 |
访问数组、集合的时候,地址index超过下标界限(过下界); |
|
SYS_INVALID_ROWID |
01410 |
-1410 |
将一个字符串转化为rowid的时候,发现非法; |
|
TIMEOUT_ON_RESOUCE |
00051 |
-51 |
当数据库等待一个执行资源的时候,操作cursor超时; |
|
TOO_MANY_ROWS |
01422 |
-1422 |
Select into语句返回了多条记录; |
|
VALUE_ERROR |
06502 |
-6502 |
数字算法、转换或者源于长度限制的错误; |
|
ZERO_DIVIDE |
01476 |
-1476 |
除零; |
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/17203031/viewspace-687040/ ,如需转载,请注明出处,否则将追究法律责任。