処理の例外¶
Snowflakeスクリプトのブロックでは、エラーが発生した場合に例外を発生させることができます。Snowflakeスクリプトコードで発生する例外を処理することもできます。
Snowflakeスクリプトの例外処理の概要¶
Snowflake Scripting raises an exception if an error occurs while executing a statement. For example, if a statement attempts to drop a table that doesn't exist, Snowflake Scripting raises an exception.
In a Snowflake Scripting block, you can write exception handlers that catch specific types of exceptions declared in that block and in blocks nested inside that block. In addition, for errors that can occur in your code, you can define your own exceptions that you can raise when errors occur.
ハンドラー内のステートメントが実行された後、ブロックを終了するか、ブロック内のステートメントを実行し続けるかを選択できます。詳細については、 Handling an exception in Snowflake Scripting をご参照ください。
When an exception is raised in a Snowflake Scripting block, either by your code or by a statement that fails to execute, Snowflake Scripting attempts to find a handler for that exception:
例外が発生したブロックにその例外のハンドラーがある場合は、その例外ハンドラーの先頭から実行が再開されます。
If the block doesn't have its own exception handler, then the exception can be caught by the enclosing block.
例外が複数のレイヤーの深さで発生した場合、例外は次のいずれかになるまで一度に1つのレイヤーずつ上向きに送信されます。
適切な例外ハンドラーを持つレイヤーが例外を処理します。
最も外側のレイヤーに到達した場合は、エラーが発生します。
現在のブロックまたはそれを囲むブロックに例外のハンドラーがない場合、ブロックの実行は停止し、実行のためにブロックを送信するクライアント(たとえば、 Snowsight、 SnowSQL など)は、これをSnowflakeエラーとして報告します。
別の例外の処理中に例外が発生した場合に備えて、例外ハンドラーに独自の例外ハンドラーを含めることができます。
Declaring an exception in Snowflake Scripting¶
ブロックの DECLARE セクションで独自の例外を宣言できます。例外宣言構文 で説明されている構文を使用します。例:
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
Raising a declared exception in Snowflake Scripting¶
例外を発生させるには、 RAISE コマンドを実行します。例:
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN counter;
END;
注意:Snowflake CLI、 SnowSQL、 Classic Console、 execute_stream、 execute_string メソッドを Python Connector コードで使用する場合は、代わりにこの例を使用してください(Snowflake CLI、 SnowSQL、 Classic Console、Python ConnectorでSnowflake Scriptingを使用する を参照)。
EXECUTE IMMEDIATE $$
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN counter;
END;
$$
;
If there is no handler, execution stops at the point when the exception is raised. In the example, counter is never
incremented and isn't returned.
The client that submits this block for execution --- for example, Snowsight --- reports an error and indicates that the exception was not caught:
-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
発生した例外(およびステートメントの実行に失敗したときに発生した例外)を処理するコードを追加する場合は、例外ハンドラーを作成できます。Handling an exception in Snowflake Scripting をご参照ください。
注釈
例外ハンドラーで、同じ例外を再生成する必要がある場合は、 Raising the same exception again in an exception handler in Snowflake Scripting をご参照ください。
Handling an exception in Snowflake Scripting¶
EXCEPTION 句を使用して例外をキャッチすることで例外を明示的に処理するか、囲んでいるブロックに例外を渡すことをブロックに許可します。
EXCEPTION 句内で、 WHEN 句を使用して名前別に例外を処理します。宣言した例外と組み込みの例外を処理できます。現在、Snowflakeは次の組み込み例外を提供しています。
STATEMENT_ERROR: この例外は、ステートメントの実行中にエラーが発生したことを示します。たとえば、存在しないテーブルを削除しようとすると、この例外が発生します。
EXPRESSION_ERROR: この例外は、式に関連するエラーを示します。たとえば、 VARCHAR と評価される式を作成し、その式の値を FLOAT に割り当てようとすると、このエラーが発生します。
例外ブロックの各 WHEN 句は、以下のいずれかのタイプになります。
EXIT - このブロックはハンドラー内のステートメントを実行し、現在のブロックを終了します。ブロックがこのタイプの例外を実行し、ブロックにエラーの原因となったステートメントの後にステートメントが含まれている場合、それらのステートメントは実行されません。
ブロックが内部ブロックであり、例外ハンドラーが RETURN ステートメントを含んでいない場合、実行は内部ブロックを終了し、外部ブロックのコードを続行します。
EXIT がデフォルトです。
CONTINUE - このブロックは例外ブロック内のステートメントを実行し、エラーの原因となったステートメントの直後のステートメントを続行します。
CONTINUE ハンドラーは、例外を発生させたステートメントブロックを終了することなく、例外をキャッチして処理できます。デフォルトの EXIT ハンドラーでは、ブロックでエラーが発生すると、フローは中断され、エラーが呼び出し元に返されます。ただし、 CONTINUE ハンドラーは、エラー条件がフローを中断する必要があるほど重大でない場合に使用できます。
EXCEPTION 句は、 EXIT と CONTINUE の両方のタイプの WHEN 句を持つことができます。
例外が発生した場合、次の3つの組み込み変数を読み取ることにより、例外に関する情報を取得できます。
SQLCODE: これは5桁の符号付き整数です。ユーザー定義の例外の場合、これは、 例外を宣言するための構文 に示されている
exception_numberです。SQLERRM: これはエラーメッセージです。ユーザー定義の例外の場合、これは、 例外を宣言するための構文 に示されている
exception_messageです。SQLSTATE: これは、 ANSI SQL 標準 SQLSTATE をモデルにした5文字コードです。Snowflakeは、 ANSI SQL 標準にある値以外の追加の値を使用します。
CONTINUE 型の WHEN 句を使用すると、これらの組み込み変数は、 WHEN 句で例外の原因となったエラーを反映します。WHEN 句のステートメントが完了し、ブロック内でステートメントの実行が継続されると、これらの変数の値は例外が発生する前の値を返します。
To handle all other exceptions that aren't built-in or declared, use a WHEN OTHER THEN clause. The WHEN OTHER THEN clause can be of type EXIT or CONTINUE.
例えば、例外を追跡するために次のようなエラーログテーブルがあるとします。
CREATE OR REPLACE TABLE test_error_log(
error_type VARCHAR,
error_code VARCHAR,
error_message VARCHAR,
error_state VARCHAR,
error_timestamp TIMESTAMP);
次の匿名ブロックは、例外に関する情報をテーブルに挿入し、その情報をユーザーに返します。
Tip
この例では、 DECLARE セクションで例外を定義し、その例外を処理しています。STATEMENT_ERROR 例外を処理する例では、この行からコメント(--)を削除します。
-- SELECT 1/0;
他のエラーを処理する例では、この行からコメントを削除してください。
-- LET var := 1/0;
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
-- SELECT 1/0;
-- LET var := 1/0;
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN 'My counter value: ' || counter;
EXCEPTION
WHEN STATEMENT_ERROR THEN
INSERT INTO test_error_log VALUES(
'STATEMENT_ERROR', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
RETURN OBJECT_CONSTRUCT('Error type', 'STATEMENT_ERROR',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN my_exception THEN
INSERT INTO test_error_log VALUES(
'MY_EXCEPTION', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
RETURN OBJECT_CONSTRUCT('Error type', 'MY_EXCEPTION',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN OTHER THEN
INSERT INTO test_error_log VALUES(
'OTHER', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
RETURN OBJECT_CONSTRUCT('Error type', 'Other error',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
END;
注意:Snowflake CLI、 SnowSQL、 Classic Console、 execute_stream、 execute_string メソッドを Python Connector コードで使用する場合は、代わりにこの例を使用してください(Snowflake CLI、 SnowSQL、 Classic Console、Python ConnectorでSnowflake Scriptingを使用する を参照)。
EXECUTE IMMEDIATE $$
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
-- SELECT 1/0;
-- LET var := 1/0;
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN 'My counter value: ' || counter;
EXCEPTION
WHEN STATEMENT_ERROR THEN
INSERT INTO test_error_log VALUES(
'STATEMENT_ERROR', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
RETURN OBJECT_CONSTRUCT('Error type', 'STATEMENT_ERROR',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN my_exception THEN
INSERT INTO test_error_log VALUES(
'MY_EXCEPTION', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
RETURN OBJECT_CONSTRUCT('Error type', 'MY_EXCEPTION',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN OTHER THEN
INSERT INTO test_error_log VALUES(
'OTHER', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
RETURN OBJECT_CONSTRUCT('Error type', 'Other error',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
END;
$$
;
返される値について、この例では、 OBJECT_CONSTRUCT を呼び出して例外の詳細を含むオブジェクトを構築して返すことで、各タイプの例外を処理しています。この例では、次の出力が生成されます。
+--------------------------------------+
| anonymous block |
|--------------------------------------|
| { |
| "Error type": "MY_EXCEPTION", |
| "SQLCODE": -20002, |
| "SQLERRM": "Raised MY_EXCEPTION.", |
| "SQLSTATE": "P0001" |
| } |
+--------------------------------------+
エラーがログに記録されたことを確認するには、 test_error_log テーブルをクエリすることができます。
SELECT * FROM test_error_log;
+--------------+------------+----------------------+-------------+-------------------------+
| ERROR_TYPE | ERROR_CODE | ERROR_MESSAGE | ERROR_STATE | ERROR_TIMESTAMP |
|--------------+------------+----------------------+-------------+-------------------------|
| MY_EXCEPTION | -20002 | Raised MY_EXCEPTION. | P0001 | 2025-09-05 12:15:00.068 |
+--------------+------------+----------------------+-------------+-------------------------+
前の例では、デフォルトの型( EXIT )の WHEN 句を使用しました。WHEN 句の1つが例外をキャッチした場合、 WHEN 句のステートメントを実行し、終了します。したがって、以下のコードは実行されません。
counter := counter + 1;
RETURN 'My counter value: ' || counter;
例外を処理してからブロック内のコードを実行し続けたい場合は、 CONTINUE 型の WHEN 句を指定します。次の例は前の例と同じですが、 CONTINUE 型の WHEN 句を指定し、各 WHEN 句から RETURN ステートメントを削除しています。
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
-- SELECT 1/0;
-- LET var := 1/0;
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN 'My counter value: ' || counter;
EXCEPTION
WHEN STATEMENT_ERROR CONTINUE THEN
INSERT INTO test_error_log VALUES(
'STATEMENT_ERROR', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
WHEN my_exception CONTINUE THEN
INSERT INTO test_error_log VALUES(
'MY_EXCEPTION', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
WHEN OTHER CONTINUE THEN
INSERT INTO test_error_log VALUES(
'OTHER', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
END;
注意:Snowflake CLI、 SnowSQL、 Classic Console、 execute_stream、 execute_string メソッドを Python Connector コードで使用する場合は、代わりにこの例を使用してください(Snowflake CLI、 SnowSQL、 Classic Console、Python ConnectorでSnowflake Scriptingを使用する を参照)。
EXECUTE IMMEDIATE $$
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
-- SELECT 1/0;
-- LET var := 1/0;
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN 'My counter value: ' || counter;
EXCEPTION
WHEN STATEMENT_ERROR CONTINUE THEN
INSERT INTO test_error_log VALUES(
'STATEMENT_ERROR', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
WHEN my_exception CONTINUE THEN
INSERT INTO test_error_log VALUES(
'MY_EXCEPTION', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
WHEN OTHER CONTINUE THEN
INSERT INTO test_error_log VALUES(
'OTHER', :sqlcode, :sqlerrm, :sqlstate, CURRENT_TIMESTAMP());
END;
$$
;
+---------------------+
| anonymous block |
|---------------------|
| My counter value: 1 |
+---------------------+
出力は、例外が発生した後も例が次のコードの実行を継続したことを示しています。
counter := counter + 1;
RETURN counter;
For more information about CONTINUE handlers, see EXCEPTION (Snowflakeスクリプト).
In rare cases, you might want to explicitly handle an exception by doing nothing. This enables you to continue, rather than terminate, when the exception occurs. For more information, see the NULL command.
注釈
同じ例外を再生成する必要がある場合は、 Raising the same exception again in an exception handler in Snowflake Scripting をご参照ください。
If you don't set up a handler for an exception, the client that submits the block for execution; for example, Snowsight reports an error as explained in Raising a declared exception in Snowflake Scripting.
-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
Raising the same exception again in an exception handler in Snowflake Scripting¶
場合によっては、例外ハンドラーでキャッチしたのと同じ例外を生成する必要が生じる可能性があります。このような場合は、引数を指定せずに RAISE コマンドを実行します。
たとえば、例外処理中に、同じ例外を再生成する前に、例外に関する詳細をキャプチャする必要があるとします。詳細をキャプチャした後に、 RAISE コマンドを実行します。
BEGIN
SELECT * FROM non_existent_table;
EXCEPTION
WHEN OTHER THEN
LET LINE := SQLCODE || ': ' || SQLERRM;
INSERT INTO myexceptions VALUES (:line);
RAISE; -- Raise the same exception that you are handling.
END;
注意:Snowflake CLI、 SnowSQL、 Classic Console、 execute_stream、 execute_string メソッドを Python Connector コードで使用する場合は、代わりにこの例を使用してください(Snowflake CLI、 SnowSQL、 Classic Console、Python ConnectorでSnowflake Scriptingを使用する を参照)。
EXECUTE IMMEDIATE $$
BEGIN
SELECT * FROM non_existent_table;
EXCEPTION
WHEN OTHER THEN
LET LINE := SQLCODE || ': ' || SQLERRM;
INSERT INTO myexceptions VALUES (:line);
RAISE; -- Raise the same exception that you are handling.
END;
$$;
Passing variables to an exception handler in Snowflake Scripting¶
例外ハンドラーに変数を渡すことができます。例外ハンドラーは変数の値に基づいてコードを実行することができ、変数の値はエラーメッセージで返すことができます。
変数を EXCEPTION セクションのハンドラーに渡すには、 DECLARE セクションでその変数を宣言する必要があります。ブロックの BEGIN... END セクションで宣言された変数は、 EXCEPTION セクションではアクセスできません。
さらに、引数を受け付ける Snowflake Scripting ストアド プロシージャを記述する場合、それらの引数を例外ハンドラーで使用できます。
例えば、以下の匿名ブロックは、 counter_val 変数の値を例外ハンドラーに渡します。
DECLARE
counter_val INTEGER DEFAULT 0;
my_exception EXCEPTION (-20002, 'My exception text');
BEGIN
WHILE (counter_val < 12) DO
counter_val := counter_val + 1;
IF (counter_val > 10) THEN
RAISE my_exception;
END IF;
END WHILE;
RETURN counter_val;
EXCEPTION
WHEN my_exception THEN
RETURN 'Error ' || sqlcode || ': Counter value ' || counter_val || ' exceeds the limit of 10.';
END;
注意:Snowflake CLI、 SnowSQL、 Classic Console、 execute_stream、 execute_string メソッドを Python Connector コードで使用する場合は、代わりにこの例を使用してください(Snowflake CLI、 SnowSQL、 Classic Console、Python ConnectorでSnowflake Scriptingを使用する を参照)。
EXECUTE IMMEDIATE $$
DECLARE
counter_val INTEGER DEFAULT 0;
my_exception EXCEPTION (-20002, 'My exception text');
BEGIN
WHILE (counter_val < 12) DO
counter_val := counter_val + 1;
IF (counter_val > 10) THEN
RAISE my_exception;
END IF;
END WHILE;
RETURN counter_val;
EXCEPTION
WHEN my_exception THEN
RETURN 'Error ' || sqlcode || ': Counter value ' || counter_val || ' exceeds the limit of 10.';
END;
$$
;
このブロックは次のエラーメッセージを返します。
+---------------------------------------------------------+
| anonymous block |
|---------------------------------------------------------|
| Error -20002: Counter value 11 exceeds the limit of 10. |
+---------------------------------------------------------+
以下は、引数を渡す Snowflake Scripting ストアドプロシージャの例です。この例では、例外ハンドラで引数を使用する方法を示しています。
CREATE OR REPLACE PROCEDURE exception_test_vars(amount INT)
RETURNS TEXT
LANGUAGE SQL
AS
DECLARE
my_exception_1 EXCEPTION (-20002, 'Value too low');
my_exception_2 EXCEPTION (-20003, 'Value too high');
BEGIN
CREATE OR REPLACE TABLE test_order_insert(units INT);
IF (amount < 1) THEN
RAISE my_exception_1;
ELSEIF (amount > 10) THEN
RAISE my_exception_2;
ELSE
INSERT INTO test_order_insert VALUES (:amount);
END IF;
RETURN 'Order inserted successfully.';
EXCEPTION
WHEN my_exception_1 THEN
RETURN 'Error ' || sqlcode || ': Submitted amount ' || amount || ' is too low (1 or greater required).';
WHEN my_exception_2 THEN
RETURN 'Error ' || sqlcode || ': Submitted amount ' || amount || ' is too high (exceeds limit of 10).';
END;
注意:Snowflake CLI、 SnowSQL、 Classic Console、 execute_stream、 execute_string メソッドを Python Connector コードで使用する場合は、代わりにこの例を使用してください(Snowflake CLI、 SnowSQL、 Classic Console、Python ConnectorでSnowflake Scriptingを使用する を参照)。
CREATE OR REPLACE PROCEDURE exception_test_vars(amount INT)
RETURNS TEXT
LANGUAGE SQL
AS
$$
DECLARE
my_exception_1 EXCEPTION (-20002, 'Value too low');
my_exception_2 EXCEPTION (-20003, 'Value too high');
BEGIN
CREATE OR REPLACE TABLE test_order_insert(units INT);
IF (amount < 1) THEN
RAISE my_exception_1;
ELSEIF (amount > 10) THEN
RAISE my_exception_2;
ELSE
INSERT INTO test_order_insert VALUES (:amount);
END IF;
RETURN 'Order inserted successfully.';
EXCEPTION
WHEN my_exception_1 THEN
RETURN 'Error ' || sqlcode || ': Submitted amount ' || amount || ' is too low (1 or greater required).';
WHEN my_exception_2 THEN
RETURN 'Error ' || sqlcode || ': Submitted amount ' || amount || ' is too high (exceeds limit of 10).';
END;
$$
;
以下のストアド・プロシージャの呼び出しは、期待される出力を示しています。
CALL exception_test_vars(7);
+------------------------------+
| EXCEPTION_TEST_VARS |
|------------------------------|
| Order inserted successfully. |
+------------------------------+
CALL exception_test_vars(-3);
+-----------------------------------------------------------------------+
| EXCEPTION_TEST_VARS |
|-----------------------------------------------------------------------|
| Error -20002: Submitted amount -3 is too low (1 or greater required). |
+-----------------------------------------------------------------------+
CALL exception_test_vars(20);
+----------------------------------------------------------------------+
| EXCEPTION_TEST_VARS |
|----------------------------------------------------------------------|
| Error -20003: Submitted amount 20 is too high (exceeds limit of 10). |
+----------------------------------------------------------------------+