TRY...CATCH (Transact-SQL)

Implementiert die Fehlerbehandlung für Transact-SQL, die Ähnlichkeiten mit der Ausnahmebehandlung in den Sprachen Microsoft Visual C# und Microsoft Visual C++ hat. Eine Gruppe von Transact-SQL-Anweisungen kann in einen TRY-Block eingeschlossen werden. Wenn innerhalb des TRY-Blocks ein Fehler auftritt, wird die Steuerung an eine andere Gruppe von Anweisungen innerhalb eines CATCH-Blocks übergeben.

Themenlink (Symbol)Transact-SQL-Syntaxkonventionen

Syntax

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

Argumente

  • sql_statement
    Eine beliebige Transact-SQL-Anweisung.

  • statement_block
    Eine beliebige Gruppe von Transact-SQL-Anweisungen in einem Batch oder in einem BEGIN…END-Block.

Hinweise

Ein TRY…CATCH-Konstrukt fängt alle Ausführungsfehler ab, deren Schweregrad größer als 10 ist und durch die die Datenbankverbindung nicht geschlossen wird.

Auf einen TRY-Block muss direkt ein dazugehöriger CATCH-Block folgen. Werden andere Anweisungen zwischen die END TRY- und BEGIN CATCH-Anweisungen eingeschlossen, wird dadurch ein Syntaxfehler generiert.

Ein TRY…CATCH-Konstrukt darf sich nicht über mehrere Batches erstrecken. Ein TRY…CATCH-Konstrukt darf sich nicht über mehrere Blocks von Transact-SQL-Anweisungen erstrecken. So darf sich ein TRY…CATCH-Konstrukt beispielsweise nicht über zwei BEGIN…END-Blöcke von Transact-SQL-Anweisungen und nicht über ein IF…ELSE-Konstrukt erstrecken.

Ist der Code in einem TRY-Block fehlerfrei, wird nach Abschluss der letzten Anweisung im TRY-Block die Steuerung an die Anweisung übergeben, die direkt auf die dazugehörige END CATCH-Anweisung folgt. Enthält der in einen TRY-Block eingeschlossene Code einen Fehler, wird die Steuerung an die erste Anweisung im dazugehörigen CATCH-Block übergeben. Ist die END CATCH-Anweisung die letzte Anweisung in einer gespeicherten Prozedur oder in einem Trigger, wird die Steuerung wieder an die Anweisung zurückgegeben, die die gespeicherte Prozedur aufgerufen bzw. den Trigger ausgelöst hat.

Wenn die Ausführung des Codes im CATCH-Block abgeschlossen ist, wird die Steuerung an die Anweisung übergeben, die direkt auf die END CATCH-Anweisung folgt. Fehler, die von einem CATCH-Block aufgefangen werden, werden nicht an die aufrufende Anwendung zurückgegeben. Falls Fehlerinformationen an die Anwendung zurückgegeben werden sollen, müssen im Code im CATCH-Block dafür bestimmte Mechanismen verwendet werden, wie z. B. SELECT-Resultsets oder die Anweisungen RAISERROR und PRINT. Weitere Informationen zum Verwenden von RAISERROR zusammen mit TRY…CATCH finden Sie unter Verwenden von TRY...CATCH in Transact-SQL.

TRY…CATCH-Konstrukte können geschachtelt werden. Entweder ein TRY- oder ein CATCH-Block kann geschachtelte TRY…CATCH-Konstrukte enthalten. So kann beispielsweise ein CATCH-Block ein eingebettetes TRY…CATCH-Konstrukt enthalten, das Fehler behandelt, die vom CATCH-Code festgestellt werden.

Fehler, die in einem CATCH-Block festgestellt werden, werden wie alle anderen Fehler behandelt. Wenn der CATCH-Block ein geschachteltes TRY…CATCH-Konstrukt enthält, wird bei jedem Fehler im geschachtelten TRY-Block die Steuerung an den geschachtelten CATCH-Block übergeben. Ist kein geschachteltes TRY…CATCH-Konstrukt vorhanden, wird der Fehler an den Aufrufer zurückgegeben.

TRY…CATCH-Konstrukte können nicht behandelte Fehler aus gespeicherten Prozeduren oder Triggern auffangen, die mit dem Code im TRY-Block ausgeführt werden. Alternativ dazu können die gespeicherten Prozeduren oder Trigger eigene TRY…CATCH-Konstrukte enthalten, die vom Code generierte Fehler behandeln. Wenn beispielsweise ein TRY-Block eine gespeicherte Prozedur ausführt und in dieser ein Fehler auftritt, dann gibt es folgende Möglichkeiten für die Behandlung des Fehlers:

  • Wenn die gespeicherte Prozedur kein eigenes TRY…CATCH-Konstrukt enthält, übergibt der Fehler die Steuerung an den CATCH-Block, der mit dem TRY-Block verknüpft ist, der die EXECUTE-Anweisung enthält.

  • Wenn die gespeicherte Prozedur ein TRY…CATCH-Konstrukt enthält, übergibt der Fehler die Steuerung an den CATCH-Block in der gespeicherten Prozedur. Wenn die Ausführung des Codes im CATCH-Block abgeschlossen ist, wird die Steuerung an die Anweisung zurückgegeben, die direkt auf die EXECUTE-Anweisung folgt, von der die gespeicherte Prozedur aufgerufen wurde.

GOTO-Anweisungen können nicht verwendet werden, um einen TRY- oder CATCH-Block einzugeben. GOTO-Anweisungen können verwendet werden, um innerhalb eines TRY- oder CATCH-Blocks zu einer Marke zu springen oder um einen TRY- oder CATCH-Block zu verlassen.

Das TRY…CATCH-Konstrukt kann nicht in einer benutzerdefinierten Funktion verwendet werden.

Abrufen von Fehlerinformationen

Im Bereich eines CATCH-Blocks können folgende Systemfunktionen verwendet werden, um Informationen zu dem Fehler abzurufen, der zur Ausführung des CATCH-Blocks geführt hat:

  • ERROR_NUMBER() gibt die Fehlernummer zurück.

  • ERROR_SEVERITY() gibt den Schweregrad zurück.

  • ERROR_STATE() gibt die Fehlerzustandsnummer zurück.

  • ERROR_PROCEDURE() gibt den Namen der gespeicherten Prozedur oder des Triggers zurück, in der bzw. in dem der Fehler auftrat.

  • ERROR_LINE() gibt die Zeilennummer in der Routine zurück, die den Fehler verursacht hat.

  • ERROR_MESSAGE() gibt den gesamten Text der Fehlermeldung zurück. Der Text umfasst die Werte, die für alle ersetzbaren Parameter angegeben werden, wie z. B. Längen, Objektnamen oder Zeitangaben.

Diese Funktionen geben NULL zurück, wenn sie außerhalb des Bereichs eines CATCH-Blocks aufgerufen werden. Fehlerinformationen können mithilfe dieser Funktionen an beliebiger Stelle im Bereich des CATCH-Blocks abgerufen werden. Das folgende Skript zeigt beispielsweise eine gespeicherte Prozedur, die Fehlerbehandlungsfunktionen umfasst. Im CATCH-Block eines TRY…CATCH-Konstrukts wird die gespeicherte Prozedur aufgerufen, und Informationen zum Fehler werden zurückgegeben.

USE AdventureWorks;
GO
-- 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;

Fehler, auf die sich ein TRY…CATCH-Konstrukt nicht auswirkt

TRY…CATCH-Konstrukte fangen folgende Bedingungen nicht auf:

  • Warnungen oder Informationsmeldungen mit einem Schweregrad von 10 oder niedriger.

  • Fehler mit einem Schweregrad von 20 oder höher, die dazu führen, dass die Verarbeitung des SQL Server Database Engine (Datenbankmodul)-Tasks für die Sitzung beendet wird. Wenn ein Fehler mit einem Schweregrad von 20 oder höher auftritt und die Datenbankverbindung nicht unterbrochen wird, wird der Fehler durch TRY…CATCH behandelt.

  • Warnungen, wie z. B. Clientunterbrechungsanforderungen oder unterbrochene Clientverbindungen.

  • Wenn die Sitzung von einem Systemadministrator mit der KILL-Anweisung beendet wird.

Die folgenden Fehlertypen werden von einem CATCH-Block nicht behandelt, wenn sie auf der gleichen Ausführungsebene wie das TRY…CATCH-Konstrukt auftreten:

  • Kompilierungsfehler, wie z. B. Syntaxfehler, die die Ausführung eines Batches verhindern.

  • Fehler, die bei der Neukompilierung auf Anweisungsebene auftreten, beispielsweise Fehler bei der Objektnamensauflösung, die aufgrund einer verzögerten Namensauflösung nach der Kompilierung auftreten.

Diese Fehler werden auf die Ebene zurückgegeben, auf der der Batch, die gespeicherte Prozedur oder der Trigger ausgeführt wurden.

Tritt ein Fehler bei der Kompilierung oder Neukompilierung auf Anweisungsebene auf einer niedrigeren Ausführungsebene (z. B. bei Ausführung von sp_executesql oder einer benutzerdefinierten gespeicherten Prozedur) innerhalb des TRY-Blocks auf, befindet sich der Fehler auf einer niedrigeren Ebene als das TRY…CATCH-Konstrukt und wird vom dazugehörigen CATCH-Block behandelt. Weitere Informationen finden Sie unter Verwenden von TRY...CATCH in Transact-SQL.

Das folgende Beispiel zeigt, wie ein Fehler bei der Objektnamensauflösung, der von einer SELECT-Anweisung generiert wurde, nicht vom TRY…CATCH-Konstrukt erfasst wurde. Er wird jedoch vom CATCH-Block erfasst, wenn dieselbe SELECT-Anweisung innerhalb einer gespeicherten Prozedur ausgeführt wird.

USE AdventureWorks;
GO

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

Der Fehler wird nicht erfasst, und die Steuerung wird vom TRY…CATCH-Konstrukt an die nächsthöhere Ebene weitergegeben.

Das Ausführen der SELECT-Anweisung innerhalb einer gespeicherten Prozedur führt dazu, dass der Fehler auf einer Ebene unter dem TRY-Block auftritt. Der Fehler wird dann vom TRY…CATCH-Konstrukt behandelt.

-- 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;
  • Weitere Informationen zu Batches finden Sie unter Batches.

Nicht commitfähige Transaktionen und XACT_STATE

Wenn ein Fehler, der in einem TRY-Block generiert wurde, dazu führt, dass der Status der aktuellen Transaktion ungültig wird, dann wird die Transaktion als nicht commitfähige Transaktion klassifiziert. Ein Fehler, der außerhalb eines TRY-Blocks normalerweise zur Beendigung einer Transaktion führt, hat bei Auftreten innerhalb eines TRY-Blocks zur Folge, dass eine Transaktion zu einer nicht commitfähigen Transaktion wird. Eine nicht commitfähige Transaktion kann nur Leseoperationen oder ROLLBACK TRANSACTION durchführen. Die Transaktion kann keine Transact-SQL-Anweisungen ausführen, die eine Schreiboperation oder COMMIT TRANSACTION generieren. Die XACT_STATE-Funktion gibt den Wert -1 zurück, wenn eine Transaktion als nicht commitfähige Transaktion klassifiziert wurde. Nach Abschluss einer Batchausführung wird für alle aktiven nicht commitfähigen Transaktionen von Database Engine (Datenbankmodul) ein Rollback ausgeführt. Falls keine Fehlermeldung gesendet wurde, als die Transaktion in den nicht commitfähigen Status überging, wird bei Abschluss des Batches eine Fehlermeldung an die Clientanwendung gesendet. Auf diese Weise wird angezeigt, dass eine nicht commitfähige Transaktion erkannt und ein Rollback für sie ausgeführt wurde.

Weitere Informationen zu nicht commitfähigen Transaktionen und zur XACT_STATE-Funktion finden Sie unter Verwenden von TRY...CATCH in Transact-SQL und XACT_STATE (Transact-SQL).

Beispiele

A. Verwenden von TRY…CATCH

Das folgende Beispiel zeigt eine SELECT-Anweisung, die einen Fehler aufgrund einer Division durch Null generiert. Der Fehler führt dazu, dass die Ausführung zum dazugehörigen CATCH-Block wechselt.

USE AdventureWorks;
GO

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. Verwenden von TRY…CATCH in einer Transaktion

Das folgende Beispiel zeigt die Funktionsweise eines TRY…CATCH-Blocks innerhalb einer Transaktion. Die Anweisung innerhalb des TRY-Blocks generiert einen Fehler aufgrund einer Einschränkungsverletzung.

USE AdventureWorks;
GO
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. Verwenden von TRY…CATCH mit XACT_STATE

Das folgende Beispiel zeigt, wie das TRY…CATCH-Konstrukt zur Behandlung von Fehlern verwendet wird, die innerhalb einer Transaktion auftreten. Über die XACT_STATE-Funktion wird bestimmt, ob für die Transaktion ein Commit oder ein Rollback ausgeführt werden soll. In diesem Beispiel hat SET XACT_ABORT den Wert ON. Dies bewirkt, dass die Transaktion nach dem Fehler aufgrund einer Einschränkungsverletzung nicht commitfähig ist.

USE AdventureWorks;
GO

-- 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.
    IF (XACT_STATE()) = 1
    BEGIN
        PRINT
            N'The transaction is committable.' +
            'Committing transaction.'
        COMMIT TRANSACTION;   
    END;
END CATCH;
GO