TRY...CATCH (Transact-SQL)

適用対象:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse AnalyticsAnalytics Platform System (PDW)Microsoft Fabric の SQL 分析エンドポイントMicrosoft Fabric のウェアハウス

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

Transact-SQL 構文表記規則

構文

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

Note

SQL Server 2014 (12.x) 以前のバージョンの Transact-SQL 構文を確認するには、以前のバージョンのドキュメントを参照してください。

引数

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 ステートメントの直後にあるステートメントに制御が渡されます。

注意

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

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

TRY...CATCH 構造は入れ子にすることができます。 TRY ブロックと CATCH ブロックのどちらにも、入れ子になった TRY...CATCH 構造を含めることができます。 たとえば、CATCH ブロックに TRY...CATCH 構造を埋め込み、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 構造から出て、1 つ上位のレベルに渡されます。

この 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 (Transact-SQL)」を参照してください。

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

参照

THROW (Transact-SQL)
データベース エンジン エラーの重大度
ERROR_LINE (Transact-SQL)
ERROR_MESSAGE (Transact-SQL)
ERROR_NUMBER (Transact-SQL)
ERROR_PROCEDURE (Transact-SQL)
ERROR_SEVERITY (Transact-SQL)
ERROR_STATE (Transact-SQL)
RAISERROR (Transact-SQL)
@@ERROR (Transact-SQL)
GOTO (Transact-SQL)
BEGIN...END (Transact-SQL)
XACT_STATE (Transact-SQL)
SET XACT_ABORT (Transact-SQL)