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 句を使用することで、複数のタイプの例外をキャッチできます。

  • 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 of EXIT type in the exception handler.

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

  • 例外が発生すると、ハンドラーの条件が順番にチェックされ、最初に一致した 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

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

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

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

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

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

注釈

This example uses the same exception name (e1) in the outer and inner blocks, which isn't recommended.

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

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

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

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;
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"          |
| }                              |
+--------------------------------+