Delen via


TRY...CATCH (Transact-SQL)

Van toepassing op:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse AnalyticsAnalytics Platform System (PDW)SQL Analytics-eindpunt in Microsoft FabricMagazijn in Microsoft FabricSQL-database in Microsoft Fabric Preview

Implementeert foutafhandeling voor Transact-SQL die vergelijkbaar is met de afhandeling van uitzonderingen in de talen C# en Visual C++. Een groep Transact-SQL instructies kan worden ingesloten in een TRY blok. Als er een fout optreedt in het blok, wordt het TRY besturingselement meestal doorgegeven aan een andere groep instructies die in een CATCH blok zijn opgenomen.

Transact-SQL syntaxis-conventies

Syntax

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

Arguments

sql_statement

Elke Transact-SQL instructie.

statement_block

Elke groep Transact-SQL instructies in een batch of tussen een BEGIN...END blok.

Remarks

Een TRY...CATCH constructie onderschept alle uitvoeringsfouten met een ernst die hoger is dan 10 die de databaseverbinding niet sluiten.

Een TRY blok moet onmiddellijk worden gevolgd door een gekoppeld CATCH blok. Als u andere instructies tussen de END TRY en BEGIN CATCH instructies ophaalt, wordt er een syntaxisfout gegenereerd.

Een TRY...CATCH constructie kan niet meerdere batches omvatten. Een TRY...CATCH constructie kan niet meerdere blokken van Transact-SQL instructies omvatten. Een TRY...CATCH constructie kan bijvoorbeeld niet twee BEGIN...END blokken van Transact-SQL instructies omvatten en kan geen constructie omvatten IF...ELSE .

Als er geen fouten zijn in de code die is ingesloten in een TRY blok, wordt het besturingselement direct na de bijbehorende END CATCH instructie doorgegeven aan de instructie wanneer de laatste instructie in het TRY blok is voltooid.

Als er een fout optreedt in de code die is ingesloten in een TRY blok, wordt het besturingselement doorgegeven aan de eerste instructie in het bijbehorende CATCH blok. Wanneer de code in het CATCH blok is voltooid, wordt de instructie direct na de END CATCH instructie doorgegeven.

Note

Als de END CATCH instructie de laatste instructie is in een opgeslagen procedure of trigger, wordt het besturingselement teruggegeven aan de instructie die de opgeslagen procedure wordt genoemd of de trigger wordt geactiveerd.

Fouten die worden gevangen door een CATCH blok, worden niet geretourneerd naar de aanroepende toepassing. Als een deel van de foutgegevens naar de toepassing moet worden geretourneerd, moet de code in het CATCH blok dit doen met behulp van mechanismen zoals SELECT resultatensets of de RAISERROR instructies PRINT .

TRY...CATCH constructies kunnen worden genest. TRY Een blok of blok CATCH kan geneste TRY...CATCH constructies bevatten. Een CATCH blok kan bijvoorbeeld een ingesloten TRY...CATCH constructie bevatten voor het afhandelen van fouten die door de CATCH code zijn opgetreden.

Fouten in een CATCH blok worden behandeld als fouten die ergens anders worden gegenereerd. Als het CATCH blok een geneste TRY...CATCH constructie bevat, wordt een fout in het geneste TRY blok doorgegeven aan het geneste CATCH blok. Als er geen geneste TRY...CATCH constructie is, wordt de fout teruggegeven aan de aanroeper.

TRY...CATCH constructs vangen niet-verwerkte fouten van opgeslagen procedures of triggers die door de code in het TRY blok worden uitgevoerd. De opgeslagen procedures of triggers kunnen ook hun eigen TRY...CATCH constructies bevatten om fouten te verwerken die zijn gegenereerd door hun code. Wanneer een TRY blok bijvoorbeeld een opgeslagen procedure uitvoert en er een fout optreedt in de opgeslagen procedure, kan de fout op de volgende manieren worden verwerkt:

  • Als de opgeslagen procedure geen eigen TRY...CATCH constructie bevat, retourneert de fout het besturingselement naar het CATCH blok dat is gekoppeld aan het TRY blok dat de EXECUTE instructie bevat.

  • Als de opgeslagen procedure een TRY...CATCH constructie bevat, brengt de fout het besturingselement over naar het CATCH blok in de opgeslagen procedure. Wanneer de blokcode is voltooid, wordt het CATCH besturingselement onmiddellijk na de instructie die de opgeslagen procedure wordt genoemd, teruggegeven aan de EXECUTE instructie.

GOTO instructies kunnen niet worden gebruikt om een TRY of CATCH meer blokkeringen in te voeren. GOTO instructies kunnen worden gebruikt om naar een label binnen hetzelfde TRY of CATCH blok te gaan of om een TRY of CATCH blok te verlaten.

De TRY...CATCH constructie kan niet worden gebruikt in een door de gebruiker gedefinieerde functie.

Foutinformatie ophalen

In het bereik van een CATCH blok kunnen de volgende systeemfuncties worden gebruikt om informatie te verkrijgen over de fout waardoor het CATCH blok werd uitgevoerd:

Function Description
ERROR_NUMBER Retourneert het aantal fouten.
ERROR_SEVERITY Retourneert de ernst.
ERROR_STATE Retourneert het foutstatusnummer.
ERROR_PROCEDURE Retourneert de naam van de opgeslagen procedure of trigger waar de fout is opgetreden.
ERROR_LINE Retourneert het regelnummer in de routine die de fout heeft veroorzaakt.
ERROR_MESSAGE Retourneert de volledige tekst van het foutbericht. De tekst bevat de waarden die worden opgegeven voor eventuele substitueerbare parameters, zoals lengtes, objectnamen of tijden.

Deze functies retourneren NULL als ze buiten het bereik van het CATCH blok worden aangeroepen. Foutinformatie kan worden opgehaald met behulp van deze functies vanaf elke locatie binnen het bereik van het CATCH blok. In het volgende script ziet u bijvoorbeeld een opgeslagen procedure die functies voor foutafhandeling bevat. In het CATCH blok van een TRY...CATCH constructie wordt de opgeslagen procedure aangeroepen en wordt informatie over de fout geretourneerd.

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

De ERROR_* functies werken ook in een CATCH blok binnen een systeemeigen gecompileerde opgeslagen procedure.

Fouten die niet worden beïnvloed door een TRY... CATCH-constructie

TRY...CATCH constructies vallen niet onder de volgende voorwaarden:

  • Waarschuwingen of informatieve berichten met een ernst van 10 of lager.

  • Fouten met een ernst van 20 of hoger die de verwerking van de SQL Server Database Engine-taak voor de sessie stoppen. Als er een fout optreedt met de ernst 20 of hoger en de databaseverbinding niet wordt onderbroken, TRY...CATCH wordt de fout afgehandeld.

  • Let op, zoals clientonderbrekende aanvragen of verbroken clientverbindingen.

  • Wanneer een systeembeheerder de KILL instructie gebruikt om de sessie te beëindigen.

De volgende typen fouten worden niet verwerkt door een CATCH blok wanneer deze zich voordoen op hetzelfde uitvoeringsniveau als de TRY...CATCH constructie:

  • Compileer fouten, zoals syntaxisfouten, die verhinderen dat een batch wordt uitgevoerd.

  • Fouten die optreden tijdens hercompilatie op instructieniveau, zoals fouten bij het oplossen van objectnamen die optreden na de compilatie vanwege uitgestelde naamomzetting.

  • Fouten bij het oplossen van objectnamen

Deze fouten worden geretourneerd naar het niveau waarop de batch, opgeslagen procedure of trigger is uitgevoerd.

Als er een fout optreedt tijdens de compilatie of hercompilatie op instructieniveau op een lager uitvoeringsniveau (bijvoorbeeld bij het uitvoeren sp_executesql of een door de gebruiker gedefinieerde opgeslagen procedure) binnen het TRY blok, treedt de fout op op een lager niveau dan de TRY...CATCH constructie en wordt deze verwerkt door het bijbehorende CATCH blok.

In het volgende voorbeeld ziet u hoe een objectnaamomzettingsfout die wordt gegenereerd door een SELECT instructie niet wordt onderschept door de TRY...CATCH constructie, maar door het CATCH blok wordt gevangen wanneer dezelfde SELECT instructie wordt uitgevoerd in een opgeslagen procedure.

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

De fout wordt niet onderschept en het besturingselement wordt doorgegeven aan het TRY...CATCH volgende hogere niveau.

Als u de SELECT instructie uitvoert in een opgeslagen procedure, wordt de fout op een niveau lager dan het TRY blok weergegeven. De fout wordt verwerkt door de TRY...CATCH constructie.

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

Niet-commiteerbare transacties en XACT_STATE

Als een fout die wordt gegenereerd in een TRY blok ertoe leidt dat de status van de huidige transactie ongeldig wordt gemaakt, wordt de transactie geclassificeerd als een niet-gecommitteerde transactie. Een fout die normaal gesproken een transactie buiten een TRY blok beëindigt, zorgt ervoor dat een transactie een niet-committabele status invoert wanneer de fout binnen een TRY blok optreedt. Een niet-commiteerbare transactie kan alleen leesbewerkingen of een ROLLBACK TRANSACTION. De transactie kan geen Transact-SQL instructies uitvoeren die een schrijfbewerking of een COMMIT TRANSACTION. De XACT_STATE functie retourneert een waarde van -1 als een transactie is geclassificeerd als een niet-commiteerbare transactie. Wanneer een batch is voltooid, worden actieve niet-commiteerbare transacties teruggedraaid door de database-engine. Als er geen foutbericht is verzonden wanneer de transactie een niet-gecommitteerde status heeft ingevoerd, wordt er een foutbericht verzonden naar de clienttoepassing wanneer de batch is voltooid. Dit geeft aan dat er een niet-toegewezen transactie is gedetecteerd en teruggedraaid.

Zie XACT_STATE voor meer informatie over niet-commiteerbare transacties en de XACT_STATE functie.

Examples

A. Use TRY...CATCH

In het volgende voorbeeld ziet u een SELECT instructie waarmee een fout tussen delen en nul wordt gegenereerd. De fout zorgt ervoor dat de uitvoering naar het bijbehorende CATCH blok springt.

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 gebruiken... CATCH in een transactie

In het volgende voorbeeld ziet u hoe een TRY...CATCH blok in een transactie werkt. De instructie in het TRY blok genereert een fout met een schending van beperkingen.

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 gebruiken... CATCH met XACT_STATE

In het volgende voorbeeld ziet u hoe u de constructie gebruikt voor het TRY...CATCH afhandelen van fouten die zich in een transactie voordoen. De XACT_STATE functie bepaalt of de transactie moet worden doorgevoerd of teruggedraaid. In dit voorbeeld is SET XACT_ABORTON. Hierdoor wordt de transactie ongedaan gemaakt wanneer de fout met een beperkingsfout optreedt.

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