EXCEPTION (Snowflake Scripting)¶
指定如何处理 Snowflake Scripting 块中引发的异常。
有关异常的详细信息,请参阅 处理异常。
- 另请参阅:
语法¶
EXCEPTION
WHEN <exception_name> [ OR <exception_name> ... ] [ { EXIT | CONTINUE } ] THEN
<statement>;
[ <statement>; ... ]
[ WHEN ... ]
[ WHEN OTHER [ { EXIT | CONTINUE } ] THEN ]
<statement>;
[ <statement>; ... ]
其中:
exception_name
在 当前块的 DECLARE 部分 或封闭块中定义的异常名称。
使用说明¶
每个 块 都可以有自己的异常处理程序。
Snowflake 支持每个块不超过一个异常处理程序。但是,通过使用多个
WHEN
子句,该处理程序可以捕获多种类型的异常。The
WHEN OTHER [ { EXIT | CONTINUE } ] THEN
clause catches any exception not yet specified.异常处理程序适用于声明它的块中 BEGIN 与 EXCEPTION 部分之间的语句。它不适用于该块的 DECLARE 部分。
仅当指定的异常在 范围 内时,异常处理程序才能处理该指定的异常。
If a stored procedure is intended to return a value, then it should return a value from each possible exit path, including each
WHEN
clause ofEXIT
type in the exception handler.若要在异常处理程序中使用变量,该变量必须在 DECLARE 部分或作为实参传递给存储过程。该变量不能在 BEGIN ...END 部分声明。有关更多信息,请参阅 Passing variables to an exception handler in Snowflake Scripting。
发生异常时,系统将按顺序检查处理程序条件并使用首个匹配的
WHEN
子句。在同一块内的顺序是从上到下,且会先检查内部块,然后再检查外部块。系统不会优先选择EXIT
或CONTINUE
处理程序,哪个先匹配就执行哪个。每条语句仅能匹配一个处理程序。但是,在异常处理程序主体内部遇到的所有异常都可以触发外部块异常处理程序。
在异常处理程序中,每个
WHEN
子句可以是以下类型之一:EXIT
– 块会执行处理程序中的语句,然后退出当前块。如果块运行此类型的异常,并且块在异常处理程序之后包含语句,则系统不会运行这些语句。如果块是内部块,并且异常处理程序不包含
RETURN
语句,则执行将退出内部块并继续执行外部块中的代码。EXIT
是默认值。CONTINUE
- 块执行处理程序中的语句,并继续执行紧随导致错误的语句之后的语句。
一个
EXCEPTION
子句可以同时包含EXIT
和CONTINUE
类型的WHEN
子句。对于
CONTINUE
类型的WHEN
子句,以下使用说明适用:如果错误在 分支结构 中引发,则继续执行的语句是紧接在分支结构之后的语句。
如果错误在 循环 的条件中引发,则继续执行的语句是紧接在循环之后的语句。
如果错误在循环主体中引发,则继续执行的语句是循环的下一次迭代中的语句。有关示例,请参阅 处理异常并继续。
如果错误在 RETURN 语句中引发,则继续执行的语句是紧接在
RETURN
语句之后的语句。如果错误在 嵌套存储过程 中引发,并且错误由外部作用域处理,则继续执行的语句是紧接在存储过程调用之后的语句。
请避免在
CONTINUE
类型的WHEN
子句中包含RETURN
语句。如果包含RETURN
语句,则存储过程会直接返回,而不会继续执行。
对于
CONTINUE
类型的WHEN
子句,以下示例显示了在不同情况下,紧接在导致错误的语句之后的语句是哪一条。在这些示例中,error_expression
是引发异常的表达式,continue_statement
是执行完CONTINUE
处理程序语句之后,代码在块中继续执行的语句。DECLARE ... BEGIN ... LET a := <error_expression>; <continue_statement>; ... EXCEPTION WHEN <exception_name> CONTINUE THEN ... END;
LET x := <valid_expression>; x := <error_expression>; <continue_statement>
SELECT <statement> INTO <error_expression>; <continue_statement>;
IF (<error_expression>) THEN <statement> ELSEIF (<valid_expression>) THEN <statement> ELSE <statement> END IF; <continue_statement>;
CASE (<error_expression>) WHEN (<valid_expression>) THEN <statement> ELSE <statement> END CASE; <continue_statement>
CASE (<valid_expression>) WHEN (<error_expression>) THEN <statement> WHEN (<valid_expression>) THEN <statement> ELSE <statement> END CASE; <continue_statement>
FOR i IN <valid_expression> TO <error_expression> DO <statement> END FOR <continue_statement>
WHILE <error_expression> DO <statement> END WHILE; <continue_statement>
REPEAT <statement> UNTIL <error_expression>; <continue_statement>
RETURN <error_expression>; <continue_statement>
DECLARE x int := 0; myproc PROCEDURE() RETURNS STRING AS BEGIN x := <error_expression>; <statement> END; BEGIN CALL myproc(); <continue_statement> ... END;
示例¶
The following examples declare and raise an exceptions, and handle the exceptions with exception handlers:
处理多种类型的异常¶
The following example shows an exception handler that is designed to handle more than one type of exception:
DECLARE
result VARCHAR;
exception_1 EXCEPTION (-20001, 'I caught the expected exception.');
exception_2 EXCEPTION (-20002, 'Not the expected exception!');
BEGIN
result := 'If you see this, I did not catch any exception.';
IF (TRUE) THEN
RAISE exception_1;
END IF;
RETURN result;
EXCEPTION
WHEN exception_2 THEN
RETURN SQLERRM;
WHEN exception_1 THEN
RETURN SQLERRM;
END;
注意:如果您在 Python Connector 代码中使用 Snowflake CLI、SnowSQL、Classic Console 或者 execute_stream
或 execute_string
方法,请改用本示例(请参阅 在 Snowflake CLI、SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):
EXECUTE IMMEDIATE $$
DECLARE
result VARCHAR;
exception_1 EXCEPTION (-20001, 'I caught the expected exception.');
exception_2 EXCEPTION (-20002, 'Not the expected exception!');
BEGIN
result := 'If you see this, I did not catch any exception.';
IF (TRUE) THEN
RAISE exception_1;
END IF;
RETURN result;
EXCEPTION
WHEN exception_2 THEN
RETURN SQLERRM;
WHEN exception_1 THEN
RETURN SQLERRM;
END;
$$;
The output shows that the exception handler caught the exception:
+----------------------------------+
| anonymous block |
|----------------------------------|
| I caught the expected exception. |
+----------------------------------+
处理异常并继续¶
以下示例展示了一个带有 CONTINUE
类型 WHEN
子句的异常处理程序:
DECLARE
exception_1 EXCEPTION (-20001, 'Catch and continue');
BEGIN
LET counter := 0;
IF (TRUE) THEN
RAISE exception_1;
END IF;
counter := counter + 10;
RETURN 'Counter value: ' || counter;
EXCEPTION
WHEN exception_1 CONTINUE THEN
counter := counter +1;
END;
注意:如果您在 Python Connector 代码中使用 Snowflake CLI、SnowSQL、Classic Console 或者 execute_stream
或 execute_string
方法,请改用本示例(请参阅 在 Snowflake CLI、SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):
EXECUTE IMMEDIATE $$
DECLARE
exception_1 EXCEPTION (-20001, 'Catch and continue');
BEGIN
LET counter := 0;
IF (TRUE) THEN
RAISE exception_1;
END IF;
counter := counter + 10;
RETURN 'Counter value: ' || counter;
EXCEPTION
WHEN exception_1 CONTINUE THEN
counter := counter +1;
END;
$$;
该输出显示异常处理程序捕获了异常、执行了将计数器增加 1
的语句,然后在捕获异常后执行了下一条语句,将计数器增加了 10
:
+-------------------+
| anonymous block |
|-------------------|
| Counter value: 11 |
+-------------------+
以下示例展示了当循环中引发错误时,带有 CONTINUE
类型的 WHEN
子句的异常处理程序如何工作。该示例在第一次迭代时引发错误,因为它尝试将值 10
除以 0。CONTINUE
处理程序将该错误记录在 error_log_table
中,然后块继续进行循环的下一次迭代,将 10
除以 1
。循环会继续迭代,直到 10
除以 5
且循环结束。输出为 2
:
CREATE TABLE error_log_table (handler_type VARCHAR, error_message VARCHAR);
DECLARE
x INT := 0;
BEGIN
FOR i IN 0 TO 5 DO
x := 10/i;
END FOR;
RETURN x;
EXCEPTION
WHEN EXPRESSION_ERROR CONTINUE THEN
INSERT INTO error_log_table SELECT 'continue_type', :SQLERRM;
END;
注意:如果您在 Python Connector 代码中使用 Snowflake CLI、SnowSQL、Classic Console 或者 execute_stream
或 execute_string
方法,请改用本示例(请参阅 在 Snowflake CLI、SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):
CREATE TABLE error_log_table (handler_type VARCHAR, error_message VARCHAR);
EXECUTE IMMEDIATE $$
DECLARE
x INT := 0;
BEGIN
FOR i IN 0 TO 5 DO
x := 10/i;
END FOR;
RETURN x;
EXCEPTION
WHEN EXPRESSION_ERROR CONTINUE THEN
INSERT INTO error_log_table SELECT 'continue_type', :SQLERRM;
END;
$$;
+-----------------+
| anonymous block |
|-----------------|
| 2 |
+-----------------+
在嵌套块中处理异常¶
This following example demonstrates nested blocks, and shows that an inner block can raise an exception declared in either the inner block or in an outer block:
DECLARE
e1 EXCEPTION (-20001, 'Exception e1');
BEGIN
-- Inner block.
DECLARE
e2 EXCEPTION (-20002, 'Exception e2');
selector BOOLEAN DEFAULT TRUE;
BEGIN
IF (selector) THEN
RAISE e1;
ELSE
RAISE e2;
END IF;
END;
EXCEPTION
WHEN e1 THEN
RETURN SQLERRM || ' caught in outer block.';
END;
注意:如果您在 Python Connector 代码中使用 Snowflake CLI、SnowSQL、Classic Console 或者 execute_stream
或 execute_string
方法,请改用本示例(请参阅 在 Snowflake CLI、SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):
EXECUTE IMMEDIATE $$
DECLARE
e1 EXCEPTION (-20001, 'Exception e1');
BEGIN
-- Inner block.
DECLARE
e2 EXCEPTION (-20002, 'Exception e2');
selector BOOLEAN DEFAULT TRUE;
BEGIN
IF (selector) THEN
RAISE e1;
ELSE
RAISE e2;
END IF;
END;
EXCEPTION
WHEN e1 THEN
RETURN SQLERRM || ' caught in outer block.';
END;
$$;
The output shows that the exception handler caught the exception:
+-------------------------------------+
| anonymous block |
|-------------------------------------|
| Exception e1 caught in outer block. |
+-------------------------------------+
This following example is similar to the previous example, but demonstrates nested blocks, each of which has its own exception handler:
DECLARE
result VARCHAR;
e1 EXCEPTION (-20001, 'Outer exception e1');
BEGIN
result := 'No error so far (but there will be).';
DECLARE
e1 EXCEPTION (-20101, 'Inner exception e1');
BEGIN
RAISE e1;
EXCEPTION
WHEN e1 THEN
result := 'Inner exception raised.';
RETURN result;
END;
RETURN result;
EXCEPTION
WHEN e1 THEN
result := 'Outer exception raised.';
RETURN result;
END;
注意:如果您在 Python Connector 代码中使用 Snowflake CLI、SnowSQL、Classic Console 或者 execute_stream
或 execute_string
方法,请改用本示例(请参阅 在 Snowflake CLI、SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):
EXECUTE IMMEDIATE $$
DECLARE
result VARCHAR;
e1 EXCEPTION (-20001, 'Outer exception e1');
BEGIN
result := 'No error so far (but there will be).';
DECLARE
e1 EXCEPTION (-20101, 'Inner exception e1');
BEGIN
RAISE e1;
EXCEPTION
WHEN e1 THEN
result := 'Inner exception raised.';
RETURN result;
END;
RETURN result;
EXCEPTION
WHEN e1 THEN
result := 'Outer exception raised.';
RETURN result;
END;
$$;
备注
This example uses the same exception name (e1
) in the outer and inner blocks, which isn't recommended.
该示例执行此操作是为了说明异常名称的 范围。名为 e1
的两个异常是不同的异常。
The e1
handler in the outer block doesn't handle the exception e1 that is declared and raised in the inner block.
The output shows that the inner exception handler ran:
+-------------------------+
| anonymous block |
|-------------------------|
| Inner exception raised. |
+-------------------------+
处理同一子句中的多种异常及未指定异常¶
The following example fragment shows how to perform two tasks:
Catch more than one exception in the same clause by using
OR
.Catch unspecified exceptions by using
WHEN OTHER THEN
.
EXCEPTION
WHEN MY_FIRST_EXCEPTION OR MY_SECOND_EXCEPTION OR MY_THIRD_EXCEPTION THEN
RETURN 123;
WHEN MY_FOURTH_EXCEPTION THEN
RETURN 4;
WHEN OTHER THEN
RETURN 99;
使用内置变量处理异常¶
The following example shows how to return SQLCODE, SQLERRM (SQL error message), and SQLSTATE built-in variable values when catching an exception:
DECLARE
MY_EXCEPTION EXCEPTION (-20001, 'Sample message');
BEGIN
RAISE MY_EXCEPTION;
EXCEPTION
WHEN STATEMENT_ERROR THEN
RETURN OBJECT_CONSTRUCT('Error type', 'STATEMENT_ERROR',
'SQLCODE', SQLCODE,
'SQLERRM', SQLERRM,
'SQLSTATE', SQLSTATE);
WHEN EXPRESSION_ERROR THEN
RETURN OBJECT_CONSTRUCT('Error type', 'EXPRESSION_ERROR',
'SQLCODE', SQLCODE,
'SQLERRM', SQLERRM,
'SQLSTATE', SQLSTATE);
WHEN OTHER THEN
RETURN OBJECT_CONSTRUCT('Error type', 'Other error',
'SQLCODE', SQLCODE,
'SQLERRM', SQLERRM,
'SQLSTATE', SQLSTATE);
END;
注意:如果您在 Python Connector 代码中使用 Snowflake CLI、SnowSQL、Classic Console 或者 execute_stream
或 execute_string
方法,请改用本示例(请参阅 在 Snowflake CLI、SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):
EXECUTE IMMEDIATE $$
DECLARE
MY_EXCEPTION EXCEPTION (-20001, 'Sample message');
BEGIN
RAISE MY_EXCEPTION;
EXCEPTION
WHEN STATEMENT_ERROR THEN
RETURN OBJECT_CONSTRUCT('Error type', 'STATEMENT_ERROR',
'SQLCODE', SQLCODE,
'SQLERRM', SQLERRM,
'SQLSTATE', SQLSTATE);
WHEN EXPRESSION_ERROR THEN
RETURN OBJECT_CONSTRUCT('Error type', 'EXPRESSION_ERROR',
'SQLCODE', SQLCODE,
'SQLERRM', SQLERRM,
'SQLSTATE', SQLSTATE);
WHEN OTHER THEN
RETURN OBJECT_CONSTRUCT('Error type', 'Other error',
'SQLCODE', SQLCODE,
'SQLERRM', SQLERRM,
'SQLSTATE', SQLSTATE);
END;
$$;
运行此示例将生成以下输出:
+--------------------------------+
| anonymous block |
|--------------------------------|
| { |
| "Error type": "Other error", |
| "SQLCODE": -20001, |
| "SQLERRM": "Sample message", |
| "SQLSTATE": "P0001" |
| } |
+--------------------------------+