処理の例外

Snowflakeスクリプトのブロックでは、エラーが発生した場合に例外を発生させることができます。Snowflakeスクリプトコードで発生する例外を処理することもできます。

Snowflakeスクリプトの例外処理の概要

Snowflakeスクリプトは、ステートメントの実行中にエラーが発生すると例外を発生させます。例えば、ステートメントが存在しないテーブルを削除しようとすると、Snowflakeスクリプトは例外を発生させます。

Snowflakeスクリプトのブロックでは、そのブロックおよびそのブロックの内部にネストされたブロックで宣言された特定のタイプの例外をキャッチする例外ハンドラーを記述できます。さらに、コード内で発生する可能性のあるエラーについては、エラーが発生したときに発生させる独自の例外を定義できます。

ハンドラー内のステートメントが実行された後、ブロックを終了するか、ブロック内のステートメントを実行し続けるかを選択できます。詳細については、 Snowflakeスクリプトで例外を処理する をご参照ください。

Snowflakeスクリプトのブロックで、コードまたは実行に失敗したステートメントによって例外が発生すると、Snowflakeスクリプトはその例外のハンドラーを見つけようとします。

  • 例外が発生したブロックにその例外のハンドラーがある場合は、その例外ハンドラーの先頭から実行が再開されます。

  • ブロックに独自の例外ハンドラーがない場合、例外はそれを囲むブロックによってキャッチされる可能性があります。

    例外が複数のレイヤーの深さで発生した場合、例外は次のいずれかになるまで一度に1つのレイヤーずつ上向きに送信されます。

    • 適切な例外ハンドラーを持つレイヤーが例外を処理します。

    • 最も外側のレイヤーに到達した場合は、エラーが発生します。

  • 現在のブロックまたはそれを囲むブロックに例外のハンドラーがない場合、ブロックの実行は停止し、実行のためにブロックを送信するクライアント(たとえば、 Snowsight、 SnowSQL など)は、これをSnowflakeエラーとして報告します。

別の例外の処理中に例外が発生した場合に備えて、例外ハンドラーに独自の例外ハンドラーを含めることができます。

Snowflakeスクリプトで例外を宣言する

ブロックの DECLARE セクションで独自の例外を宣言できます。例外宣言構文 で説明されている構文を使用します。例:

DECLARE
  my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
Copy

Snowflakeスクリプトで宣言された例外を発生させる

例外を発生させるには、 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;
Copy

注意:Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_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;
$$
;
Copy

ハンドラーがない場合、例外が発生した時点で実行は停止します。この例では、 counter はインクリメントされず、返されません。

実行するためにこのブロックを送信するクライアント(例: Snowsight )はエラーを報告し、例外がキャッチされなかったことを示します。

-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
Copy

発生した例外(およびステートメントの実行に失敗したときに発生した例外)を処理するコードを追加する場合は、例外ハンドラーを作成できます。Snowflakeスクリプトで例外を処理する をご参照ください。

注釈

例外ハンドラーで、同じ例外を再生成する必要がある場合は、 Snowflakeスクリプトの例外ハンドラーで同じ例外を再度発生させる をご参照ください。

Snowflakeスクリプトで例外を処理する

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 句のステートメントが完了し、ブロック内でステートメントの実行が継続されると、これらの変数の値は例外が発生する前の値を返します。

組み込みや宣言されていないその他すべての例外を処理するには、 WHEN OTHER THEN 句を使用します。 WHEN OTHER THEN 句は、 EXIT または CONTINUE 型のいずれかになります。

例えば、例外を追跡するために次のようなエラーログテーブルがあるとします。

CREATE OR REPLACE TABLE test_error_log(
  error_type VARCHAR,
  error_code VARCHAR,
  error_message VARCHAR,
  error_state VARCHAR,
  error_timestamp TIMESTAMP);
Copy

次の匿名ブロックは、例外に関する情報をテーブルに挿入し、その情報をユーザーに返します。

Tip

この例では、 DECLARE セクションで例外を定義し、その例外を処理しています。STATEMENT_ERROR 例外を処理する例では、この行からコメント(--)を削除します。

-- SELECT 1/0;
Copy

他のエラーを処理する例では、この行からコメントを削除してください。

-- LET var := 1/0;
Copy
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;
Copy

注意:Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_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;
$$
;
Copy

返される値について、この例では、 OBJECT_CONSTRUCT を呼び出して例外の詳細を含むオブジェクトを構築して返すことで、各タイプの例外を処理しています。この例では、次の出力が生成されます。

+--------------------------------------+
| anonymous block                      |
|--------------------------------------|
| {                                    |
|   "Error type": "MY_EXCEPTION",      |
|   "SQLCODE": -20002,                 |
|   "SQLERRM": "Raised MY_EXCEPTION.", |
|   "SQLSTATE": "P0001"                |
| }                                    |
+--------------------------------------+

エラーがログに記録されたことを確認するには、 test_error_log テーブルをクエリすることができます。

SELECT * FROM test_error_log;
Copy
+--------------+------------+----------------------+-------------+-------------------------+
| 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;
Copy

例外を処理してからブロック内のコードを実行し続けたい場合は、 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;
Copy

注意:Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_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;
$$
;
Copy
+---------------------+
| anonymous block     |
|---------------------|
| My counter value: 1 |
+---------------------+

出力は、例外が発生した後も例が次のコードの実行を継続したことを示しています。

counter := counter + 1;
RETURN counter;
Copy

CONTINUE ハンドラーの詳細については、 EXCEPTION (Snowflakeスクリプト) をご参照ください。

まれに、何もせずに例外を明示的に処理したい場合があります。これにより、例外が発生したときに終了するのではなく、続行することができます。詳細については、 NULL コマンドをご参照ください。

注釈

同じ例外を再生成する必要がある場合は、 Snowflakeスクリプトの例外ハンドラーで同じ例外を再度発生させる をご参照ください。

例外のハンドラーを設定しない場合は、実行するためにこのブロックを送信するクライアント(例: Snowsight )が、 Snowflakeスクリプトで宣言された例外を発生させる で説明のとおりエラーを報告します。

-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
Copy

Snowflakeスクリプトの例外ハンドラーで同じ例外を再度発生させる

場合によっては、例外ハンドラーでキャッチしたのと同じ例外を生成する必要が生じる可能性があります。このような場合は、引数を指定せずに 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;
Copy

注意:Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_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;
$$;
Copy

Snowflakeスクリプトで例外ハンドラーに変数を渡す

例外ハンドラーに変数を渡すことができます。例外ハンドラーは変数の値に基づいてコードを実行することができ、変数の値はエラーメッセージで返すことができます。

変数を 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;
Copy

注意:Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_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;
$$
;
Copy

このブロックは次のエラーメッセージを返します。

+---------------------------------------------------------+
| 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;
Copy

注意:Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_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;
$$
;
Copy

以下のストアド・プロシージャの呼び出しは、期待される出力を示しています。

CALL exception_test_vars(7);
Copy
+------------------------------+
| EXCEPTION_TEST_VARS          |
|------------------------------|
| Order inserted successfully. |
+------------------------------+
CALL exception_test_vars(-3);
Copy
+-----------------------------------------------------------------------+
| EXCEPTION_TEST_VARS                                                   |
|-----------------------------------------------------------------------|
| Error -20002: Submitted amount -3 is too low (1 or greater required). |
+-----------------------------------------------------------------------+
CALL exception_test_vars(20);
Copy
+----------------------------------------------------------------------+
| EXCEPTION_TEST_VARS                                                  |
|----------------------------------------------------------------------|
| Error -20003: Submitted amount 20 is too high (exceeds limit of 10). |
+----------------------------------------------------------------------+