標簽
[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
允許使用標簽 - 標簽的規(guī)則如下:
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
用于編寫復合語句惫皱,其可以出現(xiàn)在- 存儲過程
stored procedures
- 函數(shù)
functions
- 觸發(fā)器
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
塊內(nèi)
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
設(shè)置本地變量-
將查詢結(jié)果賦值給本地變量
select ... into var_list
打開游標韩脑,使用
fetch ... into var_list
流程控制語句
-
mysql
支持存儲程序中使用if
首量,case
加缘,iterate
拣宏,leave
宋下,loop
学歧,while
枝笨,repeat
- 函數(shù)中支持
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
- 只能出現(xiàn)在
loop
龙助,repeat
提鸟,while
中称勋,表示再次開始循環(huán)
leave
LEAVE label
- 退出具有指定標簽的控制
- 可以在
begin ... end
空厌,loop
嘲更,repeat
赋朦,while
中使用
loop
[begin_label:] LOOP
statement_list
END LOOP [end_label]
-
loop
實現(xiàn)循環(huán),通常通過leave
來退出循環(huán)琳拨,在函數(shù)中也可以使用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();
#死循環(huán),將一直進行輸出
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
- 用于終止函數(shù)的執(zhí)行,并將返回值返回給函數(shù)調(diào)用者
- 函數(shù)中至少要有一個
return
語句 - 存儲過程淹遵、觸發(fā)器济炎、事件中不應該使用
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關(guān)聯(lián)
DECLARE cursor_name CURSOR FOR select_statement
#打開已聲明的游標
OPEN cursor_name
#獲取下一行數(shù)據(jù)
FETCH [[NEXT] FROM] cursor_name INTO var_name [, var_name] ...
#關(guān)閉游標
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
來獲取關(guān)聯(lián)的select
的下一行數(shù)據(jù)- 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
只有已經(jīng)被打開的游標蜡豹,才能被關(guān)閉镜廉。如果游標沒有顯式關(guān)閉齐遵,則會在
begin ... end
塊末尾自動關(guān)閉-
服務(wù)器端游標允許在服務(wù)器端生成結(jié)果集梗摇,并只傳輸客戶端請求的行。服務(wù)器端游標被實現(xiàn)為內(nèi)部的臨時表糜烹,當其大小小于
max_heap_table_size
和tmp_table_size
的最小值時疮蹦,此臨時表為memory table
阵苇,否則是myisam table
慎玖,所以對于大型結(jié)果集笛粘,使用游標可能會很慢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
執(zhí)行中可能會出現(xiàn)需要特殊處理(Handle)
的條件(Condition)
趁怔,例如退出當前程序塊或繼續(xù)執(zhí)行。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
:整數(shù)數(shù)字鳍侣,指示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
枯跑,用于指定處理一個或多個情況惨驶。如果其中的一個情況發(fā)生,那么指定的statement
將被執(zhí)行敛助,其中statement
可以是set var_name = value
這樣的簡單語句粗卜,也可以是begin ... end
這樣的復合語句-
handler_action
表示statement
執(zhí)行后的動作,如下:-
condition
:繼續(xù)執(zhí)行當前程序 -
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
的簡寫续扔。在游標上下文中,如果沒有跟多行可用评疗,會觸發(fā)此錯誤 -
SQLEXCEPTION
:不以00
测砂,01
,02
開頭的sqlstate
的簡寫
-
-
當
Condition
被觸發(fā)百匆,且沒有對應的handle
與之關(guān)聯(lián)砌些,則-
對于
SQLEXCEPTION
:-
stored program
在觸發(fā)對應條件處退出,就像在此處有定義了exit
的handler
一樣 - 如果程序是在另一個
stored program
中調(diào)用,那么由調(diào)用者的handle
的規(guī)則去處理
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
存璃,程序?qū)⒗^續(xù)執(zhí)行仑荐,就像此處有定義了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
:- 如果條件是被正常觸發(fā)的,則表現(xiàn)為
continue
- 如果條件是被
signal
或者resignal
觸發(fā)的纵东,則表現(xiàn)為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
- 如果條件是被正常觸發(fā)的,則表現(xiàn)為
-
-
外部
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的內(nèi)容,否則輸出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
用于主動引發(fā)一個錯誤衰絮,并提供給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
- 以上值不允許設(shè)為
null
- 以上使用的字符集是
同一個變量不允許
set
多次-
simple_value_specification
即被設(shè)置的變量的值煌恢,可以是-
stored procedure
的參數(shù) - 函數(shù)的參數(shù)
-
stored procedure
中定義的本地變量 - 用戶定義的變量
- 系統(tǒng)變量
- 字面量
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
若此類型信號未進行捕獲,則立刻結(jié)束語句塊
#此類 condition_information_item_name 中值的默認值 MESSAGE_TEXT = 'Unhandled user-defined not found condition'; MYSQL_ERRNO = ER_SIGNAL_NOT_FOUND
-
大于
'02'
:表示異常-
sqlexception
可以捕獲此信號 - 若此類型信號未進行捕獲主籍,則立刻結(jié)束語句塊
#此類 condition_information_item_name 中值的默認值 MESSAGE_TEXT = 'Unhandled user-defined exception condition'; MYSQL_ERRNO = ER_SIGNAL_EXCEPTION
-
-
在調(diào)用了
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
是創(chuàng)建error condition
逛球,而resignal
是依賴已有的error condition
并能進行更改
-
resignal
和signal
的condition_value
及signal_information_item
的規(guī)則是相同的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的范圍規(guī)則
? stored program
可以包含多個handler
,當特定的條件在program
中發(fā)生時颤绕,進行調(diào)用幸海。hanlder
的適用性取決于其自身定義的位置以及其關(guān)聯(lián)的condition
:
-
begin ... end
中declare
的handler
,其范圍只適用于begin ... end
塊剩余的sql
語句奥务。如果handler
自身觸發(fā)了condition
物独,其自身無法處理這個condition
,并且begin ... end
塊內(nèi)的任何其他handler
也無法處理BEGIN -- outer block DECLARE EXIT HANDLER FOR ...; -- handler H1 DECLARE EXIT HANDLER FOR ...; -- handler H2 stmt1; stmt2; END; #H1和H2適用于由stmt1和stmt2觸發(fā)的condition氯葬,但是無論是H1還是H2都無法處理在H1和H2內(nèi)部觸發(fā)的condition
-
handler
的僅適用于declare
其本身的begin ... end
塊內(nèi)挡篓,無法處理外部引發(fā)的condition
BEGIN -- outer block BEGIN -- inner block DECLARE EXIT HANDLER FOR ...; -- handler H1 stmt1; END; stmt2; END; #在上述例子中,H1適用于由stmt1引發(fā)的condition,而不適用于stmt2引發(fā)的condition
-
handler
是否被觸發(fā)官研,不僅取決于其自身聲明的位置和條件秽澳,還受當前塊中的其他handler
影響。當condition
被觸發(fā)戏羽,服務(wù)器將搜索當前begin ... end
塊中適用的handler
担神,如果當前沒有合適的handler
,服務(wù)器將繼續(xù)搜索外部塊中的handler
始花,當服務(wù)器在指定的塊中找到了一個或者多個可用的handler
妄讯,將按照如下優(yōu)先級進行選擇- 最局部的且符合
condition
的handler
優(yōu)于外部的handler
- 關(guān)聯(lián)了
mysql error code
的handler
- 關(guān)聯(lián)了
sqlstate value
的handler
- 關(guān)聯(lián)了
sqlexception
的handler
- 關(guān)聯(lián)了
sqlwarning
、not found
的handler
- 最局部的且符合
同時具有多個可用的且優(yōu)先級相同的
handler
是可能的酷宵。比如說一條語句可能同時觸發(fā)多個general warning
并且對應的handler
都存在捞挥。此時無法保證哪個handler
會被觸發(fā)
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
參數(shù)不會被傳遞給調(diào)用者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