暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL的SQL语句 -条件处理语句(2) - DECLARE ... HANDLER 语句

林员外聊编程 2021-01-01
308
DECLARE ... HANDLER 语句
 
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 ... HANDLER 语句指定处理一个或多个条件的句柄。如果出现这些条件之一,则执行指定的 statementStatement 可以是一个简单的语句,如 SET var_name = value,也可以是使用 BEGIN END 编写的复合语句。
 
句柄声明必须出现在变量或条件声明之后。
 
handler_action 值指示在执行句柄语句后执行的操作:
 
● CONTINUE:继续执行当前程序。
 
● EXIT:执行终止在句柄声明所在的 BEGIN ... END 复合语句。即使条件发生在内部块中,也是如此。
 
● UNDO:不支持。
 
DECLARE ... HANDLER condition_value 指示激活句柄的特定条件或条件类。可以采取以下形式:
 
● mysql_error_code:表示 MySQL 错误码的整数,如 1051 表示 “unknown table”:
 
DECLARE CONTINUE HANDLER FOR 1051
BEGIN
-- body of handler
END;
 
不要使用 MySQL 错误代码 0,因为这表示成功,而不是错误条件。
 
● SQLSTATE [VALUE] sqlstate_value5个字符的字符串文本,表示 SQLSTATE 值,例如 '42S01' 表示 “unknown table”:
 
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
BEGIN
-- body of handler
END;
 
不要使用以 '00' 开头的 SQLSTATE 值,因为这些值表示成功,而不是错误条件。
 
● condition_name:以前用 DECLARE ... CONDITION 指定的条件名称。条件名称可以与 MySQL 错误代码或 SQLSTATE 值相关联。
 
● SQLWARNING:以 '01' 开头的 SQLSTATE 值缩写。
 
DECLARE CONTINUE HANDLER FOR SQLWARNING
BEGIN
-- body of handler
END;
 
● NOT FOUND:以 '02' 开头的 SQLSTATE 值的缩写。这在游标上下文中是相关的,用于控制游标到达数据集末尾时发生的操作。如果没有更多的行可用,则会出现 No Data 情况,SQLSTATE 值为 '02000'。要检测此条件,可以为它或 NOT FOUND 条件设置句柄。
 
DECLARE CONTINUE HANDLER FOR NOT FOUND
BEGIN
-- body of handler
END;
 
如果 SELECT ... INTO var_list 语句检索不到任何数据,也会触发 NOT FOUND 条件。
 
● SQLEXCEPTION:不是以 '00''01' '02' 开头的 SQLSTATE 值的缩写。
 
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
-- body of handler
END;
 
如果发生没有声明句柄的条件,则所采取的操作取决于具体的条件类:
 
● 对于 SQLEXCEPTION 条件,存储程序在引发该条件的语句处终止,就好像存在一个 EXIT 句柄一样。如果程序被另一个存储程序调用,则调用程序将使用自己的句柄选择规则来处理该条件。
 
● 对于 SQLWARNING 条件,程序将继续执行,就像有一个 CONTINUE 句柄一样。
 
● 对于 NOT FOUND 条件,如果条件正常引发,则操作为 CONTINUE。如果是通过 SIGNAL RESIGNAL 引发的,则操作是 EXIT
 
以下示例使用句柄处理 SQLSTATE '23000',该情况会在有重复键错误时发生:
 
mysql> CREATE TABLE test.t (s1 INT, PRIMARY KEY (s1));
Query OK, 0 rows affected (0.00 sec)


mysql> delimiter //


mysql> CREATE PROCEDURE handlerdemo ()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
SET @x = 1;
INSERT INTO test.t VALUES (1);
SET @x = 2;
INSERT INTO test.t VALUES (1);
SET @x = 3;
END;
//
Query OK, 0 rows affected (0.00 sec)


mysql> CALL handlerdemo()//
Query OK, 0 rows affected (0.00 sec)


mysql> SELECT @x//
+------+
| @x |
+------+
| 3 |
+------+
1 row in set (0.00 sec)
 
请注意,在过程执行之后 @x 是 3,这表明在错误发生之后,执行一直持续到过程结束。如果没有 DECLARE ... HANDLER 语句,MySQL 会在由于主键约束第二次插入失败后执行默认操作(EXIT),SELECT @x 会返回 2
 
若要忽略某个条件,请为其声明一个 CONTINUE 句柄并将其与空块相关联。例如:
 
DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;
 
块标签的范围不包括块内声明句柄的代码。因此,与句柄关联的语句不能使用 ITERATE 或 LEAVE 来引用包含句柄声明块的标签。考虑以下示例,其中 REPEAT 块具有 retry 标签:
 
CREATE PROCEDURE p ()
BEGIN
DECLARE i INT DEFAULT 3;
retry:
REPEAT
BEGIN
DECLARE CONTINUE HANDLER FOR SQLWARNING
BEGIN
ITERATE retry; # illegal
END;
IF i < 0 THEN
LEAVE retry; # legal
END IF;
SET i = i - 1;
END;
UNTIL FALSE END REPEAT;
END;
 
retry 标签在块中 IF 语句的作用域中。没有在 CONTINUE 句柄的作用域内,因此引用无效,会导致报错:
 
ERROR 1308 (42000): LEAVE with no matching label: retry
 
要避免在句柄中引用外部标签,请使用以下策略之一:
 
● 要离开块,请使用 EXIT 句柄。如果不需要块清理,则 BEGIN ... END 句柄主体可以为空:
 
DECLARE EXIT HANDLER FOR SQLWARNING BEGIN END;
 
否则,将清理语句放在句柄主体中:
 
DECLARE EXIT HANDLER FOR SQLWARNING
BEGIN
block cleanup statements
END;
 
 要继续执行,可以在 CONTINUE 句柄中设置一个状态变量,可以在闭合块中检查该状态变量以确定是否调用了该句柄。以下示例使用变量 done 来实现此目的:
 
CREATE PROCEDURE p ()
BEGIN
DECLARE i INT DEFAULT 3;
DECLARE done INT DEFAULT FALSE;
retry:
REPEAT
BEGIN
DECLARE CONTINUE HANDLER FOR SQLWARNING
BEGIN
SET done = TRUE;
END;
IF done OR i < 0 THEN
LEAVE retry;
END IF;
SET i = i - 1;
END;
UNTIL FALSE END REPEAT;
END;
 
 
官方网址:
https://dev.mysql.com/doc/refman/8.0/en/declare-handler.html
 

文章转载自林员外聊编程,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论