异常是指中断正常程序指令流的错误。PL/SQL为我们提供了引发异常的异常块,从而帮助程序员找出故障并解决它。
PL/SQL中定义了两种类型的异常
- 用户定义的异常。
- 系统定义的异常。
编写异常的语法
WHEN exception THEN statement;
声明 申报科;
开始 可执行命令;
例外 那么什么时候例外 声明1; 那么什么时候例外 声明2; [当其他人那时] /*默认异常处理代码*/
终止
注: 当其他人 关键字只应在异常处理块的末尾使用,因为稍后出现的异常处理部分不会被执行,因为控件将在执行其他部分后退出该块。
- 系统定义的例外情况:
- 命名系统异常。
- 未命名的系统异常。
这些异常是在PL/SQL中预定义的,当确定 违反了数据库规则。 系统定义的例外情况进一步分为两类:
- 命名系统异常:它们有一个系统预先定义的名称,比如ACCESS_INTO_NULL、DUP_VAL_ON_INDEX、LOGIN_DENIED等。列表非常大。
因此,我们将讨论一些最常用的例外情况:
让我们来创建一个表格。
create table geeks(g_id int , g_name varchar(20), marks int); insert into geeks values(1, 'Suraj',100); insert into geeks values(2, 'Praveen',97); insert into geeks values(3, 'Jessie', 99);
- 找不到数据 :返回SELECT INTO语句时引发 不 排。例如:
DECLARE
temp
varchar
(20);
BEGIN
SELECT
g_id
into
temp
from
geeks
where
g_name=
'GeeksforGeeks'
;
exception
WHEN
no_data_found
THEN
dbms_output.put_line(
'ERROR'
);
dbms_output.put_line(
'there is no name as'
);
dbms_output.put_line(
'GeeksforGeeks in geeks table'
);
end
;
输出:
ERROR there is no name as GeeksforGeeks in geeks table
- 太多行了 :返回SELECT INTO语句时引发 更多 不止一排。
DECLARE
temp
varchar
(20);
BEGIN
-- raises an exception as SELECT
-- into trying to return too many rows
SELECT
g_name
into
temp
from
geeks;
dbms_output.put_line(
temp
);
EXCEPTION
WHEN
too_many_rows
THEN
dbms_output.put_line(
'error trying to SELECT too many rows'
);
end
;
输出:
error trying to SELECT too many rows
- 值错误 :执行导致算术、数字、字符串、转换或约束错误的语句时,会引发此错误。此错误主要由程序员错误或无效数据输入引起。
DECLARE
temp
number;
BEGIN
SELECT
g_name
into
temp
from
geeks
where
g_name=
'Suraj'
;
dbms_output.put_line(
'the g_name is '
||
temp
);
EXCEPTION
WHEN
value_error
THEN
dbms_output.put_line(
'Error'
);
dbms_output.put_line(
'Change data type of temp to varchar(20)'
);
END
;
输出:
Error Change data type of temp to varchar(20)
- 零分 =用零除时引发异常。
DECLARE
a
int
:=10;
b
int
:=0;
answer
int
;
BEGIN
answer:=a/b;
dbms_output.put_line(
'the result after division is'
||answer);
exception
WHEN
zero_divide
THEN
dbms_output.put_line(
'dividing by zero please check the values again'
);
dbms_output.put_line(
'the value of a is '
||a);
dbms_output.put_line(
'the value of b is '
||b);
END
;
输出:
dividing by zero please check the values again the value of a is 10 the value of b is 0
- 找不到数据 :返回SELECT INTO语句时引发 不 排。例如:
- 未命名的系统异常:Oracle没有为一些被称为未命名系统异常的系统异常提供名称。这些例外 不要 经常发生。这些例外有两部分 代码和相关消息 . 处理这些异常的方法是 指定名称 使用 Pragma异常_INIT 语法:
PRAGMA EXCEPTION_INIT(exception_name, -error_number);
错误号是预定义的,其负整数范围为-20000到-20999。
例子:
DECLARE
exp exception;
pragma exception_init (exp, -20015);
n
int
:=10;
BEGIN
FOR
i
IN
1..n LOOP
dbms_output.put_line(i*i);
IF i*i=36
THEN
RAISE exp;
END
IF;
END
LOOP;
EXCEPTION
WHEN
exp
THEN
dbms_output.put_line(
'Welcome to GeeksforGeeks'
);
END
;
输出:
1 4 9 16 25 36 Welcome to GeeksforGeeks
例子:
- 将非负整数x除以y,使结果大于或等于1。
从给定的问题我们可以得出结论,存在两个例外
- 除法为零。
- 如果结果大于或等于1,则表示y小于或等于x。
DECLARE
x
int
:=&x; /*taking value
at
run
time
*/
y
int
:=&y;
div_r
float
;
exp1 EXCEPTION;
exp2 EXCEPTION;
BEGIN
IF y=0
then
raise exp1;
ELSEIF y > x
then
raise exp2;
ELSE
div_r:= x / y;
dbms_output.put_line(
'the result is '
||div_r);
END
IF;
EXCEPTION
WHEN
exp1
THEN
dbms_output.put_line(
'Error'
);
dbms_output.put_line(
'division by zero not allowed'
);
WHEN
exp2
THEN
dbms_output.put_line(
'Error'
);
dbms_output.put_line(
'y is greater than x please check the input'
);
END
;
Input 1: x = 20 y = 10 Output: the result is 2
Input 2: x = 20 y = 0 Output: Error division by zero not allowed
Input 3: x=20 y = 30 Output:<.em> Error y is greater than x please check the input
引发应用程序错误 : 它用于显示用户定义的错误消息,错误号的范围在-20000到-20999之间。当RAISE_应用程序_ERROR执行时,它返回错误消息和错误代码,看起来 与Oracle内置错误相同。
例子:
DECLARE myex EXCEPTION; n NUMBER :=10; BEGIN FOR i IN 1..n LOOP dbms_output.put_line(i*i); IF i*i=36 THEN RAISE myex; END IF; END LOOP; EXCEPTION WHEN myex THEN RAISE_APPLICATION_ERROR(-20015, 'Welcome to GeeksForGeeks' ); END ; |
输出:
Error report: ORA-20015: Welcome to GeeksForGeeks ORA-06512: at line 13 1 4 9 16 25 36
注: 该输出基于Oracle Sql developer 顺序 如果您在其他地方运行此代码,可能会发生更改。
异常处理中的作用域规则 :
- 我们不能两次声明异常,但我们可以声明 相同的 例外情况 两个不同的街区。
- 块内声明的异常是 地方的 去那个街区 全球的 到它的所有子块。
由于块只能引用局部或全局异常,所以封闭块不能引用子块中声明的异常。 如果我们在子块中重新声明全局异常,则以局部声明为准,即局部的范围更大。
例子:
DECLARE GeeksforGeeks EXCEPTION; age NUMBER:=16; BEGIN -- sub-block BEGINs DECLARE -- this declaration prevails GeeksforGeeks EXCEPTION; age NUMBER:=22; BEGIN IF age > 16 THEN RAISE GeeksforGeeks; /* this is not handled*/ END IF; END ; -- sub-block ends EXCEPTION -- Does not handle raised exception WHEN GeeksforGeeks THEN DBMS_OUTPUT.PUT_LINE ( 'Handling GeeksforGeeks exception.' ); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE ( 'Could not recognize exception GeeksforGeeks in this scope.' ); END ; |
输出:
Could not recognize exception GeeksforGeeks in this scope.
优势:
- 异常处理对于错误处理非常有用,如果没有异常处理,我们必须在每个点发出命令来检查执行错误: 例子:
Select .. .. check for 'no data found' error Select .. .. check for 'no data found' error Select .. .. check for 'no data found' error
在这里我们可以看到它不是 强健的 由于错误处理与正常处理是不分开的,如果我们遗漏了代码中的某一行,它可能会导致其他类型的错误。
- 通过异常处理,我们可以在不多次编写语句的情况下处理错误,甚至可以处理 不同的 一个异常块中的错误类型: 例子:
BEGIN SELECT ... SELECT ... SELECT ... . . . exception WHEN NO_DATA_FOUND THEN /* catches all 'no data found' errors */ ... WHEN ZERO_DIVIDE THEN /* different types of */ WHEN value_error THEN /* errors handled in same block */ ...
从上面的代码中,我们可以得出以下结论:异常处理
- 改善 可读性 通过让我们隔离错误处理例程,从而提供健壮性。
- 提供 可靠性 ,而不是在每个点检查不同类型的错误,我们可以简单地将它们写入异常块,如果存在错误,将引发异常,从而帮助程序员找出错误类型并最终解决它。
使用 :exception在现实生活中的一个用法可以在在线列车预订系统中找到。 在填写车站代码预订车票时,如果我们输入了错误的代码,它会向我们显示数据库中不存在该代码的例外情况。
参考: 您可以在这里找到所有预定义异常的列表。 预定义异常的总数