标签
[begin_label:] BEGIN
[statement_list]
END [end_label]
[begin_label:] LOOP
statement_list
END LOOP [end_label]
[begin_label:] REPEAT
statement_list
UNTIL search_condition
END REPEAT [end_label]
[begin_label:] WHILE search_condition DO
statement_list
END WHILE [end_label]
-
begin ... end
,loop
,repeat
,while
允许使用标签 - 标签的规则如下:
-
begin_label
后面必须跟着:
-
begin_label
可以不带end_label
,如果end_label
存在,则其必须与begin_label
一样create procedure Fun0() begin end; create procedure Fun1() szn : begin end szn; create procedure Fun2() szn : begin end;
-
end_label
若存在,必须匹配begin_label
-
标签最多可以包含16个字符
-
begin ... end
[begin_label:] BEGIN
[statement_list]
END [end_label]
-
begin ... end
用于编写复合语句,其可以出现在- 存储过程
stored procedures
- 函数
functions
- 触发器
triggers
- 事件
evnets
- 存储过程
-
begin ... end
是可以嵌套的
declare
-
declare
语句可以用于定义:- 本地变量
conditions
handlers
- 游标
-
declare
只能在begin ... end
中使用,且必须位于任何其他语句之前 -
declare
的顺序:- 变量和
conditions
- 游标
handler
- 变量和
存储程序中的变量
-
使用
declare
定义本地变量DECLARE var_name [, var_name] ... type [DEFAULT value]
- 上述语句在存储程序中定义本地变量
- 可以包含
default
赋予变量默认值,这个默认值可以是一个表达式 - 若无
default
则变量的默认值是null
- 本地变量的生命周期在定义其的
begin ... end
块内
delimiter $$ create procedure Fun() begin declare a int default 10; select a; begin select a; end; begin declare a int default 20; select a; end; end $$ delimiter ; call Fun(); /* a 10 a 10 a 20 */
-
使用
set
设置本地变量 -
将查询结果赋值给本地变量
-
select ... into var_list
-
打开游标,使用
fetch ... into var_list
-
流程控制语句
-
mysql
支持存储程序中使用if
,case
,iterate
,leave
,loop
,while
,repeat
- 函数中支持
return
- 不支持
for
case
#值匹配
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list] ...
[ELSE statement_list]
END CASE
#条件匹配
CASE
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list]
END CASE
-
case
匹配失败,且不包含else
子句,则会报错 - 处理
when
没有匹配的情况,此时else
可以包含一个空的begin ... end
delimiter $$
create procedure Fun(in v0 int, out v1 int, out v2 int)
begin
case
when v0 > 0 then
set v1 = v0 + 1;
set v2 = v0 + 2;
when v0 < 0 then
set v1 = v0 - 1;
set v2 = v0 - 2;
else
set v1 = v0;
set v2 = v0;
end case;
end $$
delimiter ;
call Fun(-1, @a0, @a1);
call Fun(1, @b0, @b1);
call Fun(0, @c0, @c1);
select @a0, @a1, @b0, @b1, @c0, @c1;
/*
@a0 @a1 @b0 @b1 @c0 @c1
-2 -3 2 3 0 0
*/
delimiter $$
create procedure Fun(in v0 int, out v1 int, out v2 int)
begin
case v0
when 1 then
set v1 = v0 + 1;
set v2 = v0 + 2;
when -1 then
set v1 = v0 - 1;
set v2 = v0 - 2;
else
set v1 = v0;
set v2 = v0;
end case;
end $$
delimiter ;
call Fun(-1, @a0, @a1);
call Fun(1, @b0, @b1);
call Fun(0, @c0, @c1);
select @a0, @a1, @b0, @b1, @c0, @c1;
/*
@a0 @a1 @b0 @b1 @c0 @c1
-2 -3 2 3 0 0
*/
delimiter $$
create procedure Fun(in v0 int)
begin
case
when v0 > 0 then
begin
end;
else
begin
end;
end case;
end $$
delimiter ;
call Fun(1);
if
IF search_condition THEN statement_list
[ELSEIF search_condition THEN statement_list] ...
[ELSE statement_list]
END IF
delimiter $$
create procedure Fun(in v0 int, out v1 int, out v2 int)
begin
if v0 > 0 then
set v1 = v0 + 1;
set v2 = v0 + 2;
elseif v0 < 0 then
set v1 = v0 - 1;
set v2 = v0 - 2;
else
set v1 = v0;
set v2 = v0;
end if;
end $$
delimiter ;
call Fun(-1, @a0, @a1);
call Fun(1, @b0, @b1);
call Fun(0, @c0, @c1);
select @a0, @a1, @b0, @b1, @c0, @c1;
/*
@a0 @a1 @b0 @b1 @c0 @c1
-2 -3 2 3 0 0
*/
iterate
ITERATE label
- 只能出现在
loop
,repeat
,while
中,表示再次开始循环
leave
LEAVE label
- 退出具有指定标签的控制
- 可以在
begin ... end
,loop
,repeat
,while
中使用
loop
[begin_label:] LOOP
statement_list
END LOOP [end_label]
-
loop
实现循环,通常通过leave
来退出循环,在函数中也可以使用return
来退出
delimiter $$
create procedure Fun()
begin
declare v int default 3;
szn:loop
select v;
set v = v - 1;
if v > 0 then
iterate szn;
end if;
leave szn;
end loop;
end $$
delimiter ;
call Fun();
/*
v
3
v
2
v
1
*/
drop procedure if exists Fun;
delimiter $$
create procedure Fun()
begin
declare v int default 3;
szn:loop
select v;
set v = v - 1;
end loop;
end $$
delimiter ;
call Fun();
#死循环,将一直进行输出
repeat
[begin_label:] REPEAT
statement_list
UNTIL search_condition
END REPEAT [end_label]
delimiter $$
create procedure Fun()
begin
declare v int default 3;
repeat
select v;
set v = v - 1;
until v < 0 #注意,此处不能有;
end repeat;
end $$
delimiter ;
call Fun();
/*
v
3
v
2
v
1
*/
return
RETURN expr
- 用于终止函数的执行,并将返回值返回给函数调用者
- 函数中至少要有一个
return
语句 - 存储过程、触发器、事件中不应该使用
return
while
[begin_label:] WHILE search_condition DO
statement_list
END WHILE [end_label]
delimiter $$
create procedure Fun()
begin
declare v int default 3;
while v > 0 do
select v;
set v = v - 1;
end while;
end $$
delimiter ;
call Fun();
/*
v
3
v
2
v
1
*/
游标
#声明一个游标,并将其与一个select关联
DECLARE cursor_name CURSOR FOR select_statement
#打开已声明的游标
OPEN cursor_name
#获取下一行数据
FETCH [[NEXT] FROM] cursor_name INTO var_name [, var_name] ...
#关闭游标
CLOSE cursor_name
-
mysql
支持在stored programs
中使用游标,游标具有以下属性- Asensitive: The server may or may not make a copy of its result table
- Read only: Not updatable
- Nonscrollable: Can be traversed only in one direction and cannot skip rows
-
已打开的游标,使用
fetch
来获取关联的select
的下一行数据- If no more rows are available, a No Data condition occurs with SQLSTATE value
'02000'
. To detect this condition, you can set up a handler for it (or for aNOT FOUND
condition)
- If no more rows are available, a No Data condition occurs with SQLSTATE value
-
只有已经被打开的游标,才能被关闭。如果游标没有显式关闭,则会在
begin ... end
块末尾自动关闭 -
服务器端游标允许在服务器端生成结果集,并只传输客户端请求的行。服务器端游标被实现为内部的临时表,当其大小小于
max_heap_table_size
和tmp_table_size
的最小值时,此临时表为memory table
,否则是myisam table
,所以对于大型结果集,使用游标可能会很慢show variables like 'max_heap_table_size' #16MB show variables like 'tmp_table_size' #39MB show variables like 'version' #8.0.17
游标使用示例
create table t(v0 int, name varchar(100));
insert into t(v0, name) values(0, "0"), (1, "1"), (2, "2"), (3, "3");
drop procedure if exists Fun;
delimiter $$
create procedure Fun(out vOut int)
begin
declare d int default false;
declare v int;
declare n varchar(100);
declare c cursor for select v0, name from t;
declare continue handler for not found set d = true;
open c;
create table if not exists tOut (name varchar(100));
truncate tOut;
set vOut = 0;
szn:while true do
fetch c into v, n;
if d then
leave szn;
end if;
if v % 2 then
set vOut = vOut + v;
insert into tOut(name) values(n);
end if;
end while;
close c;
end $$
delimiter ;
set @v = 0;
call Fun(@v);
select @v;
/*
@v
4
*/
select * from tOut;
/*
name
1
3
*/
条件(Condition) 处理(Handling)
-
stored program
执行中可能会出现需要特殊处理(Handle)
的条件(Condition)
,例如退出当前程序块或继续执行。handler
可以应付如下Condition
:- 普通条件,比如警告和异常
- 指定的条件,比如一个具体的错误代号。指定的条件可以命名,并且在
handler
中进行引用
条件声明
DECLARE condition_name CONDITION FOR condition_value
condition_value: {
mysql_error_code
| SQLSTATE [VALUE] sqlstate_value
}
-
declare ... condition
语句声明了一个错误情况,并进行命名,这个名字可以在declare ... handler
中进行引用 -
上述
condition_value
具有以下形式:-
mysql_error_code
:整数数字,指示mysql
错误码。不应该为0,因为0代表正确 -
SQLSTATE [VALUE] sqlstate_value
:5个字符组成的字符串,指示mysql
错误,不要使用00
开头的值,因为其代表正确-
mysql_error_code
与SQLSTATE [VALUE] sqlstate_value
可参考 https://dev.mysql.com/doc/refman/8.0/en/server-error-reference.htmlselect * from tNotExists #error 1146 (42S02):table 'd0.tNotExists' does not exist /* 则: mysql_error_code = 1146 SQLSTATE [VALUE] sqlstate_value = 42S02 */
-
-
-
使用命名的条件,使得程序更加的清晰可读。两种条件声明示例:
drop procedure if exists Fun; delimiter $$ create procedure Fun() begin declare table_is_not_exist_0 condition for 1146; declare table_is_not_exist_1 condition for sqlstate '42S02'; end $$ delimiter ;
声明处理
DECLARE handler_action HANDLER
FOR condition_value [, condition_value] ...
statement
handler_action: {
CONTINUE
| EXIT
| UNDO
}
condition_value: {
mysql_error_code
| SQLSTATE [VALUE] sqlstate_value
| condition_name
| SQLWARNING
| NOT FOUND
| SQLEXCEPTION
}
-
declare ... handle
语句声明了一个handle
,用于指定处理一个或多个情况。如果其中的一个情况发生,那么指定的statement
将被执行,其中statement
可以是set var_name = value
这样的简单语句,也可以是begin ... end
这样的复合语句 -
handler_action
表示statement
执行后的动作,如下:-
condition
:继续执行当前程序 -
exit
:表示退出声明handle
时所处的begin ... end
语句块 -
undo
:不支持
-
-
condition_value
表示用于激活handle
的指定条件或者是一类条件:-
mysql_error_code
:mysql
错误码 -
SQLSTATE [VALUE] sqlstate_value
:5个字符组成的字符串,指示mysql
错误 -
condition_name
:声明的条件名称 -
SQLWARNING
:以01
开头的sqlstate
的简写 -
NOT FOUND
:以02
开头的sqlstate
的简写。在游标上下文中,如果没有跟多行可用,会触发此错误 -
SQLEXCEPTION
:不以00
,01
,02
开头的sqlstate
的简写
-
-
当
Condition
被触发,且没有对应的handle
与之关联,则-
对于
SQLEXCEPTION
:-
stored program
在触发对应条件处退出,就像在此处有定义了exit
的handler
一样 - 如果程序是在另一个
stored program
中调用,那么由调用者的handle
的规则去处理
drop procedure if exists Fun; delimiter $$ create procedure Fun() begin signal sqlstate '03001'; select "szn"; end $$ delimiter ; call Fun(); #error 1644(03001): unhandled user-defined exception condition
drop procedure if exists Fun0; drop procedure if exists Fun1; delimiter $$ create procedure Fun0() begin signal sqlstate '03001'; select "Fun0"; end $$ create procedure Fun1() begin declare continue handler for sqlexception begin end; call Fun0(); select "szn"; end $$ delimiter ; call Fun1(); /* szn --- szn */ call Fun0(); #error 1644(03001): unhandled user-defined exception condition
-
-
对于
SQLWARNING
,程序将继续执行,就像此处有定义了continue
的handler
一样drop procedure if exists Fun; delimiter $$ create procedure Fun() begin signal sqlstate '01001'; select "szn"; end $$ delimiter ; call Fun(); /* szn --- szn */
-
对于
NOT FOUND
:- 如果条件是被正常触发的,则表现为
continue
- 如果条件是被
signal
或者resignal
触发的,则表现为exit
drop procedure if exists Fun; delimiter $$ create procedure Fun() begin declare v0 int; declare c cursor for select v from t; drop table if exists t; create table t(v int); insert into t(v) values(1); open c; fetch c into v0; select v0; fetch c into v0; select "szn"; close c; end $$ delimiter ; call Fun(); /* v0 1 error 1329 (02000): no data - zero rows fetched, selectd, or processed */
drop procedure if exists Fun; delimiter $$ create procedure Fun() begin signal sqlstate '02000'; select "szn"; end $$ delimiter ; call Fun(); #error1643 (02000): unhandled user-defined not found condition
- 如果条件是被正常触发的,则表现为
-
-
外部
label
不能在handler
中使用。所以statement
中,不允许使用leave
或者iterate
,来引用外层的label
drop procedure if exists Fun; delimiter $$ create procedure Fun() szn : begin declare continue handler for not found begin # leave szn; 非法 # iterate szn; 非法 end; end $$ delimiter ;
-
示例:
drop procedure if exists Fun; delimiter $$ create procedure Fun() begin declare table_is_not_exist_0 condition for 1146; declare continue handler for table_is_not_exist_0 begin select "Error : Table Not Found"; end; select * from t; end $$ delimiter ; call Fun(); /* 若表t存在,则输出表t的内容,否则输出Error : Table Not Found */
Signal
SIGNAL condition_value
[SET signal_information_item
[, signal_information_item] ...]
condition_value: {
SQLSTATE [VALUE] sqlstate_value
| condition_name
}
signal_information_item:
condition_information_item_name = simple_value_specification
condition_information_item_name: {
CLASS_ORIGIN
| SUBCLASS_ORIGIN
| MESSAGE_TEXT
| MYSQL_ERRNO
| CONSTRAINT_CATALOG
| CONSTRAINT_SCHEMA
| CONSTRAINT_NAME
| CATALOG_NAME
| SCHEMA_NAME
| TABLE_NAME
| COLUMN_NAME
| CURSOR_NAME
}
-
signal
用于主动引发一个错误,并提供给handler
、外部程序、客户端 -
signal
中的condition_value
指明了返回的错误,condition_value
可以是以下值:-
sqlstate
值,包含5个字符 - 使用
declare ... condition
声明的condition
的名字。此condition
必须以sqlstate
定义,而不能以mysql_error_code
定义(参见前面的condition的两种定义方式)
-
-
signal
声明语句中包含可选的多个set
语句-
condition_information_item_name
列表中包含了可以被set
的值Item Name Definition --------- ---------- CLASS_ORIGIN VARCHAR(64) SUBCLASS_ORIGIN VARCHAR(64) CONSTRAINT_CATALOG VARCHAR(64) CONSTRAINT_SCHEMA VARCHAR(64) CONSTRAINT_NAME VARCHAR(64) CATALOG_NAME VARCHAR(64) SCHEMA_NAME VARCHAR(64) TABLE_NAME VARCHAR(64) COLUMN_NAME VARCHAR(64) CURSOR_NAME VARCHAR(64) MESSAGE_TEXT VARCHAR(128) MYSQL_ERRNO SMALLINT UNSIGNED
- 以上使用的字符集是
utf8
- 以上值不允许设为
null
- 以上使用的字符集是
-
同一个变量不允许
set
多次 -
simple_value_specification
即被设置的变量的值,可以是-
stored procedure
的参数 - 函数的参数
-
stored procedure
中定义的本地变量 - 用户定义的变量
- 系统变量
- 字面量
drop procedure if exists Fun; delimiter $$ create procedure Fun(in v int) begin declare table_is_not_exist condition for sqlstate '42S02'; if v = 1 then signal sqlstate '42S03'; elseif v = 2 then signal sqlstate '42S04' set column_name = '1', table_name = '2'; else signal table_is_not_exist; end if; end $$ delimiter ; call Fun(0); #error 1644 (42S02):Unhandled user-defined exception condition call Fun(1); #error 1644 (42S03):Unhandled user-defined exception condition call Fun(2); #error 1644 (42S04):Unhandled user-defined exception condition
-
-
-
signal
一般在stored program
中使用,但他是mysql
扩展,也可以在处理程序上下文中使用signal sqlstate '42S03'; ##error 1644 (42S03):Unhandled user-defined exception condition
-
signal
在存储过程中使用的例子:drop procedure if exists Fun0; drop procedure if exists Fun1; drop procedure if exists Fun2; delimiter $$ create procedure Fun0() begin signal sqlstate value '42S02'; end $$ create procedure Fun1() begin declare exit handler for sqlexception begin end; signal sqlstate value '42S02'; end $$ create procedure Fun2() begin declare exit handler for sqlexception begin signal sqlstate value '99999' set message_text = 'szn'; end; signal sqlstate value '42S02'; end $$ delimiter ; call Fun0(); #error 1644(42S02): unhandled user-defined exception condition call Fun1(); #无错误输出 call Fun2(); #error 1644(99999): szn
drop procedure if exists Fun; delimiter $$ create procedure Fun() begin declare exit handler for sqlstate '99999' begin select "szn"; end; declare continue handler for sqlstate '42S02' begin signal sqlstate value '99999' set message_text = 'szn'; end; signal sqlstate value '42S02'; end $$ delimiter ; call fun(); #error 1644(99999):szn
-
condition_value
总是一个sqlstate
值,要么是直接指定,要么是通过condition
间接指定。sqlstate
的前两个字符指明了其类别:-
'00'
:表示成功,不允许指定此值 -
'01'
:- 表示警告
-
show warnings
可显示此signal
-
sqlwarning handler
可以捕捉这个信号
#此类 condition_information_item_name 中值的默认值 MESSAGE_TEXT = 'Unhandled user-defined warning condition'; MYSQL_ERRNO = ER_SIGNAL_WARN
-
'02'
:表示not found
-
not found handler
可以捕捉此信号 -
对游标无影响
drop table if exists t; create table t(v0 int); insert into t(v0) values(1), (2), (3); drop procedure if exists Fun; delimiter $$ create procedure Fun(out vOut int) begin declare v int; declare c cursor for select v0 from t; declare continue handler for not found begin select "szn"; end; open c; set vOut = 0; fetch c into v; set vOut = vOut + v; signal sqlstate '02000'; fetch c into v; set vOut = vOut + v; close c; end $$ delimiter ; set @v = 0; call Fun(@v); #输出szn select @v; #3
-
若此类型信号未进行捕获,则立刻结束语句块
#此类 condition_information_item_name 中值的默认值 MESSAGE_TEXT = 'Unhandled user-defined not found condition'; MYSQL_ERRNO = ER_SIGNAL_NOT_FOUND
-
-
大于
'02'
:表示异常-
sqlexception
可以捕获此信号 - 若此类型信号未进行捕获,则立刻结束语句块
#此类 condition_information_item_name 中值的默认值 MESSAGE_TEXT = 'Unhandled user-defined exception condition'; MYSQL_ERRNO = ER_SIGNAL_EXCEPTION
-
-
-
在调用了
signal
后- C API
-
mysql_sqlstate()
:返回sqlstate
值 -
mysql_errno()
:返回MYSQL_ERROR
和MESSAGE_TEXT
-
- Sql语句:
show warnings
和show errors
指明了MYSQL_ERROR
和MESSAGE_TEXT
- C API
Resignal
RESIGNAL [condition_value]
[SET signal_information_item
[, signal_information_item] ...]
condition_value: {
SQLSTATE [VALUE] sqlstate_value
| condition_name
}
signal_information_item:
condition_information_item_name = simple_value_specification
condition_information_item_name: {
CLASS_ORIGIN
| SUBCLASS_ORIGIN
| MESSAGE_TEXT
| MYSQL_ERRNO
| CONSTRAINT_CATALOG
| CONSTRAINT_SCHEMA
| CONSTRAINT_NAME
| CATALOG_NAME
| SCHEMA_NAME
| TABLE_NAME
| COLUMN_NAME
| CURSOR_NAME
}
-
在
condition handler
中,resignal
传递可更改的error condition
-
signal
是创建error condition
,而resignal
是依赖已有的error condition
并能进行更改
-
-
resignal
和signal
的condition_value
及signal_information_item
的规则是相同的 -
resignal
的condition_value
和set
子句都是可选的
单独的Resignal
- 单独的
resignal
意味着仅传递错误,不进行更改
drop procedure if exists Fun;
drop table t if exists;
delimiter $$
create procedure Fun()
begin
declare continue handler for sqlexception
begin
select "szn0";
resignal;
select "szn1";
end;
drop table t;
end $$
delimiter ;
call Fun();
/*
szn0
----
szn0
error 1051 (42S02):unknow table 'd0.t'
*/
show errors;
/*
Level Code Message
---- ---- -------------------
Error 1051 unknow table 'd0.t'
*/
drop table t;
#error 1051 (42S02):unknow table 'd0.t'
仅更改signal_information_item的Resignal
drop procedure if exists Fun;
drop table t if exists;
delimiter $$
create procedure Fun()
begin
declare continue handler for sqlexception
begin
select "szn";
resignal
set mysql_errno = 5,
message_text = "hello";
end;
drop table t;
end $$
delimiter ;
call Fun();
/*
szn
---
szn
error 5 (42S02):hello
*/
show errors;
/*
Level Code Message
---- ---- -------------------
Error 5 hello
*/
drop table t;
#error 1051 (42S02):unknow table 'd0.t'
更改condition_value及可选的signal_information_item的Resignal
drop procedure if exists Fun;
drop table t if exists;
delimiter $$
create procedure Fun()
begin
declare continue handler for sqlexception
begin
select "szn";
resignal sqlstate '04123'
set mysql_errno = 5, #可选
message_text = "hello"; #可选
end;
drop table t;
end $$
delimiter ;
call Fun();
/*
szn
---
szn
error 5 (04123):hello
*/
show errors;
/*
Level Code Message
---- ---- -------------------
Error 1051 unknow table 'd0.t'
Error 5 hello
*/
drop table t;
#error 1051 (42S02):unknow table 'd0.t'
Handler的范围规则
stored program
可以包含多个handler
,当特定的条件在program
中发生时,进行调用。hanlder
的适用性取决于其自身定义的位置以及其关联的condition
:
-
begin ... end
中declare
的handler
,其范围只适用于begin ... end
块剩余的sql
语句。如果handler
自身触发了condition
,其自身无法处理这个condition
,并且begin ... end
块内的任何其他handler
也无法处理BEGIN -- outer block DECLARE EXIT HANDLER FOR ...; -- handler H1 DECLARE EXIT HANDLER FOR ...; -- handler H2 stmt1; stmt2; END; #H1和H2适用于由stmt1和stmt2触发的condition,但是无论是H1还是H2都无法处理在H1和H2内部触发的condition
-
handler
的仅适用于declare
其本身的begin ... end
块内,无法处理外部引发的condition
BEGIN -- outer block BEGIN -- inner block DECLARE EXIT HANDLER FOR ...; -- handler H1 stmt1; END; stmt2; END; #在上述例子中,H1适用于由stmt1引发的condition,而不适用于stmt2引发的condition
-
handler
是否被触发,不仅取决于其自身声明的位置和条件,还受当前块中的其他handler
影响。当condition
被触发,服务器将搜索当前begin ... end
块中适用的handler
,如果当前没有合适的handler
,服务器将继续搜索外部块中的handler
,当服务器在指定的块中找到了一个或者多个可用的handler
,将按照如下优先级进行选择- 最局部的且符合
condition
的handler
优于外部的handler
- 关联了
mysql error code
的handler
- 关联了
sqlstate value
的handler
- 关联了
sqlexception
的handler
- 关联了
sqlwarning
、not found
的handler
- 最局部的且符合
-
同时具有多个可用的且优先级相同的
handler
是可能的。比如说一条语句可能同时触发多个general warning
并且对应的handler
都存在。此时无法保证哪个handler
会被触发
Demo
drop procedure if exists Fun0;
drop procedure if exists Fun1;
drop procedure if exists Fun2;
drop procedure if exists Fun3;
drop table if exists t;
delimiter $$
#Fun0
create procedure Fun0()
begin
declare continue handler for sqlexception
select "sql exception";
declare continue handler for sqlstate '42S02'
select "sql state";
drop table t;
end $$
#Fun1
create procedure Fun1()
begin
declare continue handler for sqlstate '42S02'
select "sql state";
begin
declare continue handler for sqlexception
select "sql exception";
drop table t;
end;
end $$
#Fun2
create procedure Fun2()
begin
declare continue handler for sqlstate '42S02'
select "sql state";
begin
declare continue handler for sqlexception
select "sql exception";
end;
drop table t;
end $$
#Fun3
create procedure Fun3()
begin
begin
declare continue handler for sqlstate '42S02'
select "sql state";
declare continue handler for sqlexception
select "sql exception";
end;
drop table t;
end $$
delimiter ;
call Fun0();
/*
sql state
---------
sql state
*/
call Fun1();
/*
sql exception
-------------
sql exception
*/
call Fun2();
/*
sql state
---------
sql state
*/
call Fun3();
#error 1051 (42S02): unknow table 'd0.t'
Condition Handling and OUT or INOUT Parameters
-
如果存储过程因为一个没有处理的
exception
而退出,被更改的out
和inout
参数不会被传递给调用者drop procedure if exists Fun; delimiter $$ create procedure Fun(out v0 int, inout v1 int) begin set v0 = 1; set v1 = 2; select "Inner", v0, v1; signal sqlstate '04001'; end $$ delimiter ; call Fun(@a, @b); /* Inner v0 v1 ------------- Inner 1 2 */ select @a, @b; /* @a @b ------------ null null */
参考
https://dev.mysql.com/doc/refman/8.0/en/sql-compound-statements.html
网友评论