TRY...CATCH (Transact-SQL)

Applies to: SQL Server Azure SQL Database Azure SQL Managed Instance Azure Synapse Analytics Analytics Platform System (PDW) Microsoft Fabric の SQL 分析エンドポイント Microsoft Fabric のウェアハウス

C# および Visual C++ 言語での例外処理に似た Transact-SQL のエラー処理を実装します。 Transact-SQL ステートメントのグループは、 TRY ブロックで囲むことができます。 TRY ブロックでエラーが発生した場合、コントロールは通常、CATCH ブロックで囲まれた別のステートメント グループに渡されます。

Transact-SQL 構文表記規則

構文

BEGIN TRY
    { sql_statement | statement_block }
END TRY
BEGIN CATCH
    [ { sql_statement | statement_block } ]
END CATCH
[ ; ]

引数

sql_statement

Transact-SQL ステートメント。

statement_block

バッチ内または BEGIN...END ブロックで囲まれた Transact-SQL ステートメントの任意のグループ。

解説

TRY...CATCH コンストラクトは、データベース接続を閉じない重大度が 10 を超えるすべての実行エラーをキャッチします。

TRY ブロックの直後に、関連付けられているCATCH ブロックが続く必要があります。 END TRY ステートメントと BEGIN CATCH ステートメントの間に他のステートメントを含めると、構文エラーが発生します。

TRY...CATCHコンストラクトは複数のバッチにまたがることができます。 TRY...CATCHコンストラクトは、Transact-SQL ステートメントの複数のブロックにまたがることができます。 たとえば、 TRY...CATCH コンストラクトは、Transact-SQL ステートメントの 2 つの BEGIN...END ブロックにまたがることはできません。またがって、 IF...ELSE コンストラクトにまたがることはありません。

TRY ブロックで囲まれたコードにエラーがない場合、TRY ブロック内の最後のステートメントが終了すると、関連付けられている END CATCH ステートメントの直後にコントロールがステートメントに渡されます。

TRY ブロックで囲まれたコードにエラーが発生した場合、コントロールは関連付けられたCATCH ブロック内の最初のステートメントに渡されます。 CATCH ブロック内のコードが終了すると、END CATCH ステートメントの直後にコントロールがステートメントに渡されます。

Note

END CATCH ステートメントがストアド プロシージャまたはトリガーの最後のステートメントである場合は、ストアド プロシージャを呼び出したステートメントまたはトリガーを起動したステートメントに制御が戻されます。

CATCH ブロックによってトラップされたエラーは、呼び出し元のアプリケーションには返されません。 エラー情報の一部をアプリケーションに返す必要がある場合、 CATCH ブロック内のコードは、 SELECT 結果セットや RAISERROR ステートメントや PRINT ステートメントなどのメカニズムを使用して返す必要があります。

TRY...CATCH コンストラクトを入れ子にすることができます。 TRY ブロックまたはCATCH ブロックには、入れ子になったTRY...CATCHコンストラクトを含めることができます。 たとえば、CATCH ブロックには、CATCH コードで発生したエラーを処理する埋め込みTRY...CATCHコンストラクトを含めることができます。

CATCH ブロックで発生したエラーは、他の場所で生成されたエラーと同様に扱われます。 CATCH ブロックに入れ子になったTRY...CATCHコンストラクトが含まれている場合、入れ子になったTRY ブロック内のエラーは、入れ子になったCATCH ブロックに制御を渡します。 入れ子になった TRY...CATCH コンストラクトがない場合、エラーは呼び出し元に返されます。

TRY...CATCH コンストラクトは、 TRY ブロック内のコードによって実行されるストアド プロシージャまたはトリガーからハンドルされないエラーをキャッチします。 または、ストアド プロシージャまたはトリガーに独自の TRY...CATCH コンストラクトを含め、コードによって生成されたエラーを処理することもできます。 たとえば、 TRY ブロックがストアド プロシージャを実行し、ストアド プロシージャでエラーが発生した場合、エラーは次の方法で処理できます。

  • ストアド プロシージャに独自のTRY...CATCHコンストラクトが含まれていない場合、エラーは、EXECUTE ステートメントを含むTRY ブロックに関連付けられているCATCH ブロックに制御を返します。

  • ストアド プロシージャに TRY...CATCH コンストラクトが含まれている場合、エラーはストアド プロシージャの CATCH ブロックに制御を転送します。 CATCH ブロック コードが終了すると、ストアド プロシージャを呼び出した EXECUTE ステートメントの直後に、コントロールがステートメントに渡されます。

GOTO ステートメントを使用して、 TRY または CATCH ブロックを入力することはできません。 GOTO ステートメントを使用すると、同じ TRY または CATCH ブロック内のラベルにジャンプしたり、 TRY または CATCH ブロックを残したりできます。

TRY...CATCH コンストラクトは、ユーザー定義関数では使用できません。

エラー情報を取得する

CATCH ブロックのスコープでは、次のシステム関数を使用して、CATCH ブロックが実行される原因となったエラーに関する情報を取得できます。

関数 説明
ERROR_NUMBER エラーの数を返します。
ERROR_SEVERITY 重大度を返します。
ERROR_STATE エラー状態番号を返します。
ERROR_PROCEDURE エラーが発生したストアド プロシージャまたはトリガーの名前を返します。
ERROR_LINE エラーの原因となったルーチン内の行番号を返します。
ERROR_MESSAGE エラー メッセージの完全なテキストを返します。 このテキストには、長さ、オブジェクト名、回数など、置き換え可能なパラメーターに提供される値が含まれます。

これらの関数は、CATCH ブロックのスコープ外で呼び出された場合、NULLを返します。 エラー情報は、 CATCH ブロックのスコープ内の任意の場所からこれらの関数を使用して取得できます。 たとえば、次のスクリプトは、エラー処理関数を含むストアド プロシージャです。 CATCH 構造の TRY...CATCH ブロックでは、このストアド プロシージャを呼び出して、エラーに関する情報を返しています。

-- Verify that the stored procedure does not already exist.
IF OBJECT_ID('usp_GetErrorInfo', 'P') IS NOT NULL
    DROP PROCEDURE usp_GetErrorInfo;
GO

-- Create procedure to retrieve error information.
CREATE PROCEDURE usp_GetErrorInfo
AS
SELECT ERROR_NUMBER() AS ErrorNumber,
    ERROR_SEVERITY() AS ErrorSeverity,
    ERROR_STATE() AS ErrorState,
    ERROR_PROCEDURE() AS ErrorProcedure,
    ERROR_LINE() AS ErrorLine,
    ERROR_MESSAGE() AS ErrorMessage;
GO

BEGIN TRY
    -- Generate divide-by-zero error.
    SELECT 1 / 0;
END TRY

BEGIN CATCH
    -- Execute error retrieval routine.
    EXECUTE usp_GetErrorInfo;
END CATCH;

ERROR_*関数は、にコンパイルされたストアド プロシージャ内のCATCH ブロックでも機能

TRY の影響を受けないエラー...CATCH コンストラクト

TRY...CATCH コンストラクトは、次の条件をトラップしません。

  • 重大度が 10 以下の警告または情報メッセージ。

  • 重大度が 20 以上で、そのセッションの SQL Server データベース エンジン タスク処理を終了させるエラー。 重大度が 20 以上のエラーが発生し、データベース接続が中断されない場合は、 TRY...CATCH がエラーを処理します。

  • クライアントの割り込み要求や中断されたクライアント接続などのアテンション。

  • システム管理者が KILL ステートメントを使用してセッションを終了する場合。

次の種類のエラーは、TRY...CATCH コンストラクトと同じ実行レベルで発生した場合、CATCH ブロックでは処理されません。

  • 構文エラーなど、バッチの実行を妨げるコンパイル エラー。

  • ステートメントレベルの再コンパイルで発生するエラー (コンパイル後の名前の遅延解決により発生するオブジェクト名の解決エラーなど)。

  • オブジェクト名解決エラー

これらのエラーは、バッチ、ストアド プロシージャ、またはトリガーを実行したレベルに返されます。

コンパイル中またはステートメント レベルの再コンパイル中に、TRY ブロック内のより低い実行レベル (たとえば、sp_executesqlまたはユーザー定義ストアド プロシージャの実行時) でエラーが発生した場合、エラーはTRY...CATCHコンストラクトよりも低いレベルで発生し、関連付けられているCATCH ブロックによって処理されます。

次の例は、SELECT ステートメントによって生成されたオブジェクト名解決エラーがTRY...CATCHコンストラクトによってキャッチされず、ストアド プロシージャ内で同じSELECT ステートメントが実行されたときにCATCH ブロックによってキャッチされる方法を示しています。

BEGIN TRY
    -- Table does not exist; object name resolution
    -- error not caught.
    SELECT *
    FROM NonexistentTable;
END TRY

BEGIN CATCH
    SELECT ERROR_NUMBER() AS ErrorNumber,
        ERROR_MESSAGE() AS ErrorMessage;
END CATCH

エラーはキャッチされず、制御は TRY...CATCH コンストラクトから次の上位レベルに渡されます。

ストアド プロシージャ内で SELECT ステートメントを実行すると、 TRY ブロックより低いレベルでエラーが発生します。 エラーは、 TRY...CATCH コンストラクトによって処理されます。

-- Verify that the stored procedure does not exist.
IF OBJECT_ID(N'usp_ExampleProc', N'P') IS NOT NULL
    DROP PROCEDURE usp_ExampleProc;
GO

-- Create a stored procedure that will cause an
-- object resolution error.
CREATE PROCEDURE usp_ExampleProc
AS
SELECT *
FROM NonexistentTable;
GO

BEGIN TRY
    EXECUTE usp_ExampleProc;
END TRY

BEGIN CATCH
    SELECT ERROR_NUMBER() AS ErrorNumber,
        ERROR_MESSAGE() AS ErrorMessage;
END CATCH;

コミットできないトランザクションとXACT_STATE

TRY ブロックでエラーが発生すると、現在のトランザクションの状態が無効になると、トランザクションはコミット不可能なトランザクションとして分類されます。 通常、 TRY ブロックの外部でトランザクションを終了するエラーでは、 TRY ブロック内でエラーが発生すると、トランザクションはコミットできない状態になります。 コミットできないトランザクションは、読み取り操作または ROLLBACK TRANSACTIONのみを実行できます。 トランザクションは、書き込み操作または COMMIT TRANSACTIONを生成する Transact-SQL ステートメントを実行できません。 トランザクションがコミット不可能なトランザクションとして分類されている場合、 XACT_STATE 関数は -1 の値を返します。 バッチが完了すると、データベース エンジンによってコミット不可能なトランザクションがロールバックされます。 トランザクションがコミットできない状態になったときにエラー メッセージが送信されなかった場合、バッチが完了すると、エラー メッセージがクライアント アプリケーションに送信されます。 これは、コミット不可能なトランザクションが検出され、ロールバックされたことを示します。

コミットできないトランザクションと XACT_STATE 関数の詳細については、 XACT_STATEを参照してください。

A. TRY...CATCH を使用する

次の例は、0 除算エラーを生成する SELECT ステートメントを示しています。 このエラーにより、関連する CATCH ブロックに実行が移動します。

BEGIN TRY
    -- Generate a divide-by-zero error.
    SELECT 1 / 0;
END TRY

BEGIN CATCH
    SELECT ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() AS ErrorState,
        ERROR_PROCEDURE() AS ErrorProcedure,
        ERROR_LINE() AS ErrorLine,
        ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO

B. TRY を使用しています...トランザクション内の CATCH

次の例では、トランザクション内での TRY...CATCH ブロックの動作を示しています。 TRY ブロック内のステートメントにより、制約違反エラーが生成されます。

BEGIN TRANSACTION;

BEGIN TRY
    -- Generate a constraint violation error.
    DELETE
    FROM Production.Product
    WHERE ProductID = 980;
END TRY

BEGIN CATCH
    SELECT ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() AS ErrorState,
        ERROR_PROCEDURE() AS ErrorProcedure,
        ERROR_LINE() AS ErrorLine,
        ERROR_MESSAGE() AS ErrorMessage;

    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END CATCH;

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
GO

C: TRY を使用しています...CATCH with XACT_STATE

次の例では、TRY...CATCH 構造を使用して、トランザクション内で発生するエラーを処理する方法を示しています。 XACT_STATE 関数により、トランザクションをコミットすべきか、またはロールバックすべきかが決定されます。 この例では SET XACT_ABORTON です。 これにより、制約違反エラーが発生したときに、トランザクションはコミット不可能になります。

-- Check to see whether this stored procedure exists.
IF OBJECT_ID(N'usp_GetErrorInfo', N'P') IS NOT NULL
    DROP PROCEDURE usp_GetErrorInfo;
GO

-- Create procedure to retrieve error information.
CREATE PROCEDURE usp_GetErrorInfo
AS
SELECT ERROR_NUMBER() AS ErrorNumber,
    ERROR_SEVERITY() AS ErrorSeverity,
    ERROR_STATE() AS ErrorState,
    ERROR_LINE() AS ErrorLine,
    ERROR_PROCEDURE() AS ErrorProcedure,
    ERROR_MESSAGE() AS ErrorMessage;
GO

-- SET XACT_ABORT ON will cause the transaction to be uncommittable
-- when the constraint violation occurs.
SET XACT_ABORT ON;

BEGIN TRY
    BEGIN TRANSACTION;

    -- A FOREIGN KEY constraint exists on this table. This
    -- statement will generate a constraint violation error.
    DELETE
    FROM Production.Product
    WHERE ProductID = 980;

    -- If the DELETE statement succeeds, commit the transaction.
    COMMIT TRANSACTION;
END TRY

BEGIN CATCH
    -- Execute error retrieval routine.
    EXECUTE usp_GetErrorInfo;

    -- Test XACT_STATE:
    -- If 1, the transaction is committable.
    -- If -1, the transaction is uncommittable and should
    --     be rolled back.
    -- XACT_STATE = 0 means that there is no transaction and
    --     a commit or rollback operation would generate an error.
    -- Test whether the transaction is uncommittable.
    IF (XACT_STATE()) = -1
    BEGIN
        PRINT N'The transaction is in an uncommittable state. Rolling back transaction.'

        ROLLBACK TRANSACTION;
    END;

    -- Test whether the transaction is committable.
    -- You may want to commit a transaction in a catch block if you want to commit changes to statements that ran prior to the error.
    IF (XACT_STATE()) = 1
    BEGIN
        PRINT N'The transaction is committable. Committing transaction.'

        COMMIT TRANSACTION;
    END;
END CATCH;
GO