EXCEPTION (Snowflakeスクリプト)

Snowflakeスクリプトのブロックで発生した例外の処理方法を指定します。

例外の詳細については、 処理の例外 をご参照ください。

こちらもご参照ください:

RAISE

構文

EXCEPTION
    WHEN <exception_name> [ OR <exception_name> ... ] [ { EXIT | CONTINUE } ] THEN
        <statement>;
        [ <statement>; ... ]
    [ WHEN ... ]
    [ WHEN OTHER [ { EXIT | CONTINUE } ] THEN ]
        <statement>;
        [ <statement>; ... ]
Copy

条件:

exception_name

現在のブロックの DECLARE 部分、またはそれを囲むブロックで定義された例外名。

statement

ステートメントは、次のいずれかになります。

  • 単一の SQL ステートメント(CALL を含む)。

  • 制御フローステートメント(例: ループ または 分岐 ステートメント)。

  • ネストされた ブロック

使用上の注意

  • ブロック は、独自の例外ハンドラーを持つことができます。

  • Snowflakeは、ブロックごとに1つだけの例外ハンドラーをサポートします。ただし、そのハンドラーは、複数の WHEN 句を使用することで、複数のタイプの例外をキャッチできます。

  • WHEN OTHER [ { EXIT | CONTINUE } ] THEN 句は、まだ指定されていない例外をキャッチします。

  • 例外ハンドラーは、それが宣言されたブロックの BEGIN と EXCEPTION セクションの間のステートメントに適用されます。ブロックの DECLARE セクションには適用されません。

  • 例外ハンドラーは、指定された例外が スコープ にある場合にのみ、指定された例外を処理できます。

  • ストアドプロシージャが値を返すことを目的としている場合は、例外ハンドラーの EXIT 型の WHEN 句を含む、可能な各終了パスから値を返す必要があります。

  • 例外ハンドラで変数を使うには、変数を DECLARE セクションで宣言するか、ストアドプロシージャに引数として渡す必要があります。BEGIN ... END セクションでは宣言できません。詳細については、 Snowflakeスクリプトで例外ハンドラーに変数を渡す をご参照ください。

  • 例外が発生すると、ハンドラーの条件が順番にチェックされ、最初に一致した WHEN 句が使われます。ブロック内の順序は上から下になり、内側のブロックは外側のブロックより先にチェックされます。EXIT または CONTINUE ハンドラーのマッチングに優先順位はなく、先に一致した方が使用されます。

  • 1つのステートメントに一致するハンドラーは1つだけです。しかし、例外ハンドラー本体の内側で発生した例外は、外側のブロックの例外ハンドラーをトリガーすることができます。

  • 例外ハンドラーの各 WHEN 句は、以下のいずれかのタイプになります。

    • EXIT - このブロックはハンドラー内のステートメントを実行し、現在のブロックを終了します。ブロックがこのタイプの例外を実行し、ブロックに例外ハンドラーの後にステートメントが含まれている場合、それらのステートメントは実行されません。

      ブロックが内側のブロックであり、例外ハンドラーが RETURN ステートメントを含んでいない場合、実行は内側のブロックを終了し、外側のブロックのコードを続行します。

      EXIT がデフォルトです。

    • CONTINUE - このブロックはハンドラー内のステートメントを実行し、エラーの原因となったステートメントの直後のステートメントを続行します。

    EXCEPTION 句は、 EXITCONTINUE の両方の型の 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;
    
    Copy
    LET x := <valid_expression>;
    x := <error_expression>;
    <continue_statement>
    
    Copy
    SELECT <statement> INTO <error_expression>;
    <continue_statement>;
    
    Copy
    IF (<error_expression>) THEN
      <statement>
    ELSEIF (<valid_expression>) THEN
      <statement>
    ELSE
      <statement>
    END IF;
    <continue_statement>;
    
    Copy
    CASE (<error_expression>)
      WHEN (<valid_expression>) THEN
        <statement>
      ELSE
        <statement>
    END CASE;
    <continue_statement>
    
    Copy
    CASE (<valid_expression>)
      WHEN (<error_expression>) THEN
        <statement>
      WHEN (<valid_expression>) THEN
        <statement>
      ELSE
        <statement>
    END CASE;
    <continue_statement>
    
    Copy
    FOR i IN <valid_expression> TO <error_expression> DO
      <statement>
    END FOR
    <continue_statement>
    
    Copy
    WHILE <error_expression> DO
      <statement>
    END WHILE;
    <continue_statement>
    
    Copy
    REPEAT
      <statement>
    UNTIL <error_expression>;
    <continue_statement>
    
    Copy
    RETURN <error_expression>;
    <continue_statement>
    
    Copy
    DECLARE
      x int := 0;
      myproc PROCEDURE()
        RETURNS STRING
        AS BEGIN
          x := <error_expression>;
          <statement>
        END;
    BEGIN
      CALL myproc();
      <continue_statement>
      ...
    END;
    
    Copy

以下の例では、例外を宣言して発生させ、例外ハンドラーで例外を処理しています。

複数の型の例外を処理する

次の例は、複数の型の例外を処理するように設計された例外ハンドラーを示しています。

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

注意:Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_string メソッドを Python Connector コードで使用する場合は、代わりにこの例を使用してください(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;
$$;
Copy

この出力は、例外ハンドラーが例外をキャッチしたことを示しています。

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

注意:Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_string メソッドを Python Connector コードで使用する場合は、代わりにこの例を使用してください(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;
$$;
Copy

出力は、例外ハンドラーが例外をキャッチし、カウンターに 1 を追加するステートメントを実行し、例外がキャッチされた後に次のステートメントを実行して、カウンターに 10 を追加したことを示しています。

+-------------------+
| anonymous block   |
|-------------------|
| Counter value: 11 |
+-------------------+

次の例は、 CONTINUE 型の WHEN 句を持つ例外ハンドラーが、ループ内でエラーが発生したときにどのように動作するかを示しています。この例では、値 10 をゼロで割ろうとしているため、最初の繰り返しでエラーが発生します。CONTINUE ハンドラーは error_log_table にエラーを記録し、ブロックは 101 で割るループの次の繰り返しを続行します。ループは、 105 で割られ、ループが終了するまで繰り返されます。出力は 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;
Copy

注意:Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_string メソッドを Python Connector コードで使用する場合は、代わりにこの例を使用してください(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;
$$;
Copy
+-----------------+
| anonymous block |
|-----------------|
|               2 |
+-----------------+

ネストされたブロックで例外を処理する

次の例はネストされたブロックを示しており、内側のブロックが、内側のブロックまたは外側のブロックのどちらかで宣言された例外を発生させる可能性があることを示しています。

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

注意:Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_string メソッドを Python Connector コードで使用する場合は、代わりにこの例を使用してください(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;
$$;
Copy

この出力は、例外ハンドラーが例外をキャッチしたことを示しています。

+-------------------------------------+
| anonymous block                     |
|-------------------------------------|
| Exception e1 caught in outer block. |
+-------------------------------------+

次の例は前の例と似ていますが、ネストされたブロックを示しています。各ブロックには独自の例外ハンドラーがあります。

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

注意:Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_string メソッドを Python Connector コードで使用する場合は、代わりにこの例を使用してください(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;
$$;
Copy

注釈

この例では、外側と内側のブロックで同じ例外名( e1 )を使用していますが、これは推奨されません。

この例では、例外名の スコープ を説明するためにこれを実行しています。e1 という名前の2つの例外は、異なる例外です。

外側のブロックの e1 ハンドラーは、内側のブロックで宣言および発生した例外e1を処理しません。

この出力は、内側の例外ハンドラーが実行されたことを示しています。

+-------------------------+
| anonymous block         |
|-------------------------|
| Inner exception raised. |
+-------------------------+

同一句内の複数の例外と不特定例外を処理する

次の例は、2つのタスクを実行する方法を示しています。

  • OR を使用して、同じ句で複数の例外をキャッチします。

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

組み込み変数を使用して例外を処理する

次の例は、例外をキャッチしたときに SQLCODE 、 SQLERRM ( SQL エラーメッセージ)、 SQLSTATE 組み込み変数値 を返す方法を示しています。

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

注意:Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_string メソッドを Python Connector コードで使用する場合は、代わりにこの例を使用してください(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;
$$;
Copy

この例を実行すると、次の出力が生成されます。

+--------------------------------+
| anonymous block                |
|--------------------------------|
| {                              |
|   "Error type": "Other error", |
|   "SQLCODE": -20001,           |
|   "SQLERRM": "Sample message", |
|   "SQLSTATE": "P0001"          |
| }                              |
+--------------------------------+