Documentation Home
MySQL 8.0 参考手册  / 第 13 章 SQL 语句  / 13.6 复合语句语法  / 13.6.7 条件处理  /  13.6.7.2 DECLARE ... HANDLER 语句

13.6.7.2 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语句指定处理一个或多个条件的处理程序。如果这些条件之一发生,则statement执行指定的。 statement可以是简单的语句,例如, 或使用and 编写的复合语句(请参阅第 13.6.1 节,“BEGIN ... END 复合语句”)。 SET var_name = valueBEGINEND

处理程序声明必须出现在变量或条件声明之后。

handler_action值指示处理程序在执行处理程序语句后采取的操作:

  • CONTINUE:继续执行当前程序。

  • EXITBEGIN ... END:对于声明处理程序的复合语句,执行终止 。即使条件发生在内部块中也是如此。

  • UNDO: 不支持。

condition_valuefor DECLARE ... HANDLER指示激活处理程序的特定条件或条件类别 。它可以采用以下形式:

  • mysql_error_code:表示MySQL错误代码的整数文字,例如1051表示未知表

    DECLARE CONTINUE HANDLER FOR 1051
      BEGIN
        -- body of handler
      END;

    不要使用 MySQL 错误代码 0,因为它表示成功而不是错误情况。有关 MySQL 错误代码的列表,请参阅服务器错误消息参考

  • SQLSTATE [VALUE] sqlstate_value:一个 5 个字符的字符串文字,表示一个 SQLSTATE 值,例如'42S01'指定未知表

    DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
      BEGIN
        -- body of handler
      END;

    不要使用以 开头的 SQLSTATE 值, '00'因为这些值表示成功而不是错误情况。有关 SQLSTATE 值的列表,请参阅服务器错误消息参考

  • condition_name: 之前用 指定的条件名称 DECLARE ... CONDITION。条件名称可以与 MySQL 错误代码或 SQLSTATE 值相关联。请参阅 第 13.6.7.1 节,“DECLARE ... CONDITION 语句”

  • SQLWARNING: 以 开头的 SQLSTATE 值类的简写'01'

    DECLARE CONTINUE HANDLER FOR SQLWARNING
      BEGIN
        -- body of handler
      END;
  • NOT FOUND: 以 开头的 SQLSTATE 值类的简写'02'。这在游标上下文中是相关的,用于控制游标到达数据集末尾时发生的情况。如果没有更多行可用,则出现 No Data 条件,SQLSTATE value '02000'。要检测此条件,您可以为其或条件设置一个处理程序NOT FOUND

    DECLARE CONTINUE HANDLER FOR NOT FOUND
      BEGIN
        -- body of handler
      END;

    对于另一个示例,请参阅第 13.6.6 节,“游标”。对于未检索任何行 NOT FOUND的语句,也会出现 这种 情况。SELECT ... INTO var_list

  • SQLEXCEPTION'00':不以、'01'或 开头的 SQLSTATE 值类的简写 '02'

    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
      BEGIN
        -- body of handler
      END;

有关在条件发生时服务器如何选择处理程序的信息,请参阅第 13.6.7.6 节,“处理程序的作用域规则”

如果发生没有声明处理程序的条件,则采取的操作取决于条件类:

  • 对于SQLEXCEPTION条件,存储的程序在引发条件的语句处终止,就好像有一个EXIT 处理程序一样。如果该程序被另一个存储程序调用,则调用程序使用应用于其自己的处理程序的处理程序选择规则来处理该条件。

  • 对于SQLWARNING条件,程序继续执行,就好像有一个 CONTINUE处理程序一样。

  • 对于NOT FOUND条件,如果条件正常出现,则操作为 CONTINUE。如果它是由 SIGNALor 引发的RESIGNAL,则操作为 EXIT

以下示例使用处理程序 for 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)

请注意,这@x3在过程执行之后,这表明在发生错误后,执行一直持续到过程结束。如果该 DECLARE ... HANDLER语句不存在,MySQL 将在第二次由于约束而 失败EXIT后采取默认操作 () ,并返回 。 INSERTPRIMARY KEYSELECT @x2

要忽略条件,请为其声明一个CONTINUE 处理程序并将其与一个空块相关联。例如:

DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;

块标签的范围不包括块内声明的处理程序的代码。因此,与处理程序关联的语句不能使用 ITERATELEAVE引用包含处理程序声明的块的标签。考虑以下示例,其中 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;