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
可以是一個簡單的陳述式,例如 SET
,或是一個使用 var_name
= value
BEGIN
和 END
撰寫的複合陳述式(請參閱第 15.6.1 節,「BEGIN ... END 複合陳述式」)。
處理常式的宣告必須出現在變數或條件宣告之後。
handler_action
值表示處理常式在執行處理常式陳述式後所採取的動作。
CONTINUE
:繼續執行目前的程式。EXIT
:終止宣告處理常式的BEGIN ... END
複合陳述式的執行。即使條件發生在內部區塊中,也是如此。UNDO
:不支援。
DECLARE ... HANDLER
的 condition_value
表示會啟動處理常式的特定條件或條件類別。它可以採用以下形式:
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;
請勿使用以
'00'
開頭的 SQLSTATE 值,因為它們表示成功而不是錯誤條件。如需 SQLSTATE 值的清單,請參閱伺服器錯誤訊息參考。condition_name
:先前使用DECLARE ... CONDITION
指定的條件名稱。條件名稱可以與 MySQL 錯誤代碼或 SQLSTATE 值相關聯。請參閱第 15.6.7.1 節,「DECLARE ... CONDITION 陳述式」。SQLWARNING
:以'01'
開頭的 SQLSTATE 值類別的簡寫。DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN -- body of handler END;
NOT FOUND
:以'02'
開頭的 SQLSTATE 值類別的簡寫。這在游標的上下文中很重要,用於控制當游標到達資料集的末尾時發生的情況。如果沒有更多列可用,則會發生 SQLSTATE 值為'02000'
的「無資料」條件。若要偵測此條件,您可以為它或NOT FOUND
條件設定處理常式。DECLARE CONTINUE HANDLER FOR NOT FOUND BEGIN -- body of handler END;
另一個範例,請參閱第 15.6.6 節,「游標」。
SELECT ... INTO
陳述式如果沒有檢索到任何列,也會發生var_list
NOT FOUND
條件。SQLEXCEPTION
:不以'00'
、'01'
或'02'
開頭的 SQLSTATE 值類別的簡寫。DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN -- body of handler END;
如需有關伺服器在發生條件時如何選擇處理常式的資訊,請參閱第 15.6.7.6 節,「處理常式的範圍規則」。
如果發生未宣告任何處理常式的條件,則採取的動作取決於條件類別。
以下範例使用 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 在第二個 INSERT
因 PRIMARY KEY
限制而失敗後,會採取預設動作 (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;