Freigeben über


TRY...CATCH (Transact-SQL)

Gilt für: SQL Server Azure SQL-Datenbank Azure SQL Managed Instance Azure Synapse Analytics Analytics Platform System (PDW) SQL-Analyseendpunkt in Microsoft Fabric Warehouse in Microsoft Fabric SQL-Datenbank in Microsoft Fabric

Implementiert die Fehlerbehandlung für Transact-SQL, die der Ausnahmebehandlung in den Sprachen C# und Visual C++ ähnelt. Eine Gruppe von Transact-SQL-Anweisungen kann in einen TRY Block eingeschlossen werden. Wenn im Block ein Fehler auftritt, wird das Steuerelement in der TRY Regel an eine andere Gruppe von Anweisungen übergeben, die in einen CATCH Block eingeschlossen sind.

Transact-SQL-Syntaxkonventionen

Syntax

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

Argumente

sql_statement

Jede Transact-SQL-Anweisung.

statement_block

Jede Gruppe von Transact-SQL-Anweisungen in einem Batch oder in einen BEGIN...END Block eingeschlossen.

Hinweise

Ein TRY...CATCH Konstrukt erfasst alle Ausführungsfehler, die einen Schweregrad über 10 haben, der die Datenbankverbindung nicht schließt.

Auf TRY einen Block muss sofort ein zugeordneter CATCH Block folgen. Wenn Sie andere Anweisungen zwischen den END TRY Anweisungen einschließen BEGIN CATCH , wird ein Syntaxfehler generiert.

Ein TRY...CATCH Konstrukt kann nicht mehrere Batches umfassen. Ein TRY...CATCH Konstrukt kann nicht mehrere Blöcke von Transact-SQL-Anweisungen umfassen. Ein Konstrukt kann beispielsweise TRY...CATCH keine zwei BEGIN...END Blöcke von Transact-SQL-Anweisungen umfassen und kann kein Konstrukt umfassen IF...ELSE .

Wenn kein Fehler im Code vorhanden ist, der in einen TRY Block eingeschlossen ist, wird das Steuerelement nach Abschluss der letzten Anweisung im TRY Block an die END CATCH Anweisung übergeben.

Wenn im Code, der in einen TRY Block eingeschlossen ist, ein Fehler auftritt, wird das Steuerelement an die erste Anweisung im zugeordneten CATCH Block übergeben. Wenn der Code im CATCH Block abgeschlossen ist, wird das Steuerelement unmittelbar nach der Anweisung an die END CATCH Anweisung übergeben.

Hinweis

Wenn es sich bei der END CATCH Anweisung um die letzte Anweisung in einer gespeicherten Prozedur oder einem Trigger handelt, wird das Steuerelement an die Anweisung übergeben, die die gespeicherte Prozedur aufgerufen oder den Trigger ausgelöst hat.

Fehler, die von einem CATCH Block abgefangen werden, werden nicht an die aufrufende Anwendung zurückgegeben. Wenn ein Teil der Fehlerinformationen an die Anwendung zurückgegeben werden muss, muss der Code im CATCH Block dies mithilfe von Mechanismen wie SELECT Resultsets oder den RAISERROR Anweisungen PRINT tun.

TRY...CATCH Konstrukte können geschachtelt werden. Ein TRY Block oder ein CATCH Block kann geschachtelte Konstrukte TRY...CATCH enthalten. Ein Block kann z. B. ein eingebettetes TRY...CATCH Konstrukt enthalten, um Fehler zu behandeln, CATCH die CATCH vom Code aufgetreten sind.

Fehler, die in einem CATCH Block aufgetreten sind, werden wie Fehler behandelt, die an einer anderen Stelle generiert werden. Wenn der CATCH Block ein geschachteltes TRY...CATCH Konstrukt enthält, übergibt ein Fehler im geschachtelten TRY Block das Steuerelement an den geschachtelten CATCH Block. Wenn kein geschachteltes TRY...CATCH Konstrukt vorhanden ist, wird der Fehler an den Aufrufer übergeben.

TRY...CATCH erstellt unbehandelte Fehler aus gespeicherten Prozeduren oder Triggern, die vom Code im TRY Block ausgeführt werden. Alternativ können die gespeicherten Prozeduren oder Trigger eigene TRY...CATCH Konstrukte zum Behandeln von Fehlern enthalten, die durch ihren Code generiert werden. Wenn beispielsweise ein TRY Block eine gespeicherte Prozedur ausführt und ein Fehler in der gespeicherten Prozedur auftritt, kann der Fehler wie folgt behandelt werden:

  • Wenn die gespeicherte Prozedur kein eigenes TRY...CATCH Konstrukt enthält, gibt der Fehler das Steuerelement an den Block zurück, der CATCH dem Block zugeordnet ist, der TRY die EXECUTE Anweisung enthält.

  • Wenn die gespeicherte Prozedur ein TRY...CATCH Konstrukt enthält, überträgt das Fehlersteuerelement an den CATCH Block in der gespeicherten Prozedur. Wenn der CATCH Blockcode abgeschlossen ist, wird das Steuerelement unmittelbar nach der EXECUTE Anweisung, die die gespeicherte Prozedur aufgerufen hat, an die Anweisung zurückgesendet.

GOTO Anweisungen können nicht zum Eingeben oder TRY CATCH Blockieren verwendet werden. GOTO Anweisungen können verwendet werden, um zu einer Beschriftung innerhalb desselben TRY oder Blocks zu springen oder CATCH einen TRY Block zu CATCH verlassen.

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

Abrufen von Fehlerinformationen

Im Bereich eines CATCH Blocks können die folgenden Systemfunktionen verwendet werden, um Informationen zu dem Fehler abzurufen, der dazu führte, dass der CATCH Block ausgeführt wurde:

Funktion Beschreibung
ERROR_NUMBER Gibt die Nummer des Fehlers zurück.
ERROR_SEVERITY Gibt den Schweregrad zurück.
ERROR_STATE Gibt die Fehlerstatusnummer zurück.
ERROR_PROCEDURE Gibt den Namen der gespeicherten Prozedur zurück oder löst den Fehler aus.
ERROR_LINE Gibt die Zeilennummer innerhalb der Routine zurück, die den Fehler verursacht hat.
ERROR_MESSAGE Gibt den vollständigen 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 werden zurückgegeben NULL , wenn sie außerhalb des Bereichs des CATCH Blocks aufgerufen werden. Fehlerinformationen können mithilfe dieser Funktionen von überall innerhalb des CATCH Blockbereichs 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.

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

Die ERROR_* Funktionen funktionieren auch in einem CATCH Block innerhalb einer nativ kompilierten gespeicherten Prozedur.

Fehler, die von einem TRY nicht betroffen sind... CATCH-Konstrukt

TRY...CATCH Konstrukte führen nicht die folgenden Bedingungen durch:

  • 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-Datenbank-Engine-Tasks für die Sitzung beendet wird. Wenn ein Fehler auftritt, der den Schweregrad von 20 oder höher aufweist und die Datenbankverbindung nicht unterbrochen wird, TRY...CATCH wird der Fehler behandelt.

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

  • Wenn ein Systemadministrator die KILL Anweisung zum Beenden der Sitzung verwendet.

Die folgenden Arten von Fehlern werden nicht von einem CATCH Block behandelt, wenn sie auf derselben Ausführungsebene wie das TRY...CATCH Konstrukt auftreten:

  • Kompilierungsfehler, 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.

  • Fehler bei der Auflösung von Objektnamen

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

Wenn während der Kompilierung oder der Neukompilierung auf Anweisungsebene auf niedrigerer Ausführungsebene (z. B. beim Ausführen sp_executesql oder einer benutzerdefinierten gespeicherten Prozedur) innerhalb des TRY Blocks ein Fehler auftritt, tritt der Fehler auf einer niedrigeren Ebene als das TRY...CATCH Konstrukt auf und wird vom zugeordneten CATCH Block behandelt.

Das folgende Beispiel zeigt, wie ein von einer SELECT Anweisung generierter Fehler bei der Objektnamenauflösung nicht vom TRY...CATCH Konstrukt abgefangen wird, aber vom CATCH Block abgefangen wird, wenn dieselbe SELECT Anweisung in einer gespeicherten Prozedur ausgeführt wird.

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 abgefangen, und die Steuerung übergibt das TRY...CATCH Konstrukt auf die nächste höhere Ebene.

Wenn Sie die SELECT Anweisung in einer gespeicherten Prozedur ausführen, tritt der Fehler auf einer Ebene unter dem TRY Block auf. Der Fehler wird 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;

Nicht ansetzbare Transaktionen und XACT_STATE

Wenn ein in einem TRY Block generierter Fehler bewirkt, dass der Status der aktuellen Transaktion ungültig wird, wird die Transaktion als nichtmittbare Transaktion klassifiziert. Ein Fehler, der eine Transaktion außerhalb eines TRY Blocks beendet, führt dazu, dass eine Transaktion einen nicht aussetzbaren Zustand eingibt, wenn der Fehler innerhalb eines TRY Blocks auftritt. Eine nicht aussetzbare Transaktion kann nur Lesevorgänge oder eine ROLLBACK TRANSACTION. Die Transaktion kann keine Transact-SQL-Anweisungen ausführen, die einen Schreibvorgang oder einen COMMIT TRANSACTION. Die XACT_STATE Funktion gibt einen Wert zurück, der -1 angibt, ob eine Transaktion als unkommittierbare Transaktion klassifiziert wurde. Nach Abschluss einer Batchausführung wird für alle aktiven nicht commitfähigen Transaktionen von Datenbank-Engine ein Rollback ausgeführt. Wenn keine Fehlermeldung gesendet wurde, wenn die Transaktion einen nicht aussetzbaren Zustand eingegeben hat, wird beim 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 nichtmittierbaren Transaktionen und der XACT_STATE Funktion finden Sie unter XACT_STATE.

Beispiele

A. Verwenden von TRY... CATCH

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

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 Sie 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.

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 Sie 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.

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