Dela via


TRY...CATCH (Transact-SQL)

Gäller för:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse AnalyticsAnalysplattformssystem (PDW)SQL-analysslutpunkt i Microsoft FabricLager i Microsoft FabricSQL-databas i Förhandsversion av Microsoft Fabric

Implementerar felhantering för Transact-SQL som liknar undantagshanteringen på språken C# och Visual C++. En grupp med Transact-SQL-instruktioner kan omges av ett TRY block. Om ett fel inträffar i TRY blocket skickas kontrollen vanligtvis till en annan grupp med instruktioner som omges av ett CATCH block.

Transact-SQL syntaxkonventioner

Syntax

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

Arguments

sql_statement

Alla Transact-SQL-instruktioner.

statement_block

Alla grupper med Transact-SQL-instruktioner i en batch eller omges av ett BEGIN...END block.

Remarks

En TRY...CATCH konstruktion fångar upp alla körningsfel som har en allvarlighetsgrad som är högre än 10 och som inte stänger databasanslutningen.

Ett TRY block måste omedelbart följas av ett associerat CATCH block. Om du inkluderar andra instruktioner mellan END TRY - och BEGIN CATCH -uttrycken genereras ett syntaxfel.

En TRY...CATCH konstruktion kan inte sträcka sig över flera batchar. En TRY...CATCH konstruktion kan inte sträcka sig över flera block med Transact-SQL-instruktioner. En konstruktion kan till exempel TRY...CATCH inte sträcka sig över två BEGIN...END block med Transact-SQL-instruktioner och kan inte sträcka sig över en IF...ELSE konstruktion.

Om det inte finns några fel i koden som omges av ett TRY block, när den sista instruktionen TRY i blocket är klar, skickas kontrollen till -instruktionen omedelbart efter den associerade END CATCH instruktionen.

Om det finns ett fel i koden som omges av ett TRY block skickas kontrollen till den första instruktionen i det associerade CATCH blocket. När koden i CATCH blocket är klar skickas kontrollen till -instruktionen omedelbart efter -instruktionen END CATCH .

Note

Om -instruktionen END CATCH är den sista instruktionen i en lagrad procedur eller utlösare skickas kontrollen tillbaka till -instruktionen som anropade den lagrade proceduren eller utlöste utlösaren.

Fel som fångas av ett CATCH block returneras inte till det anropande programmet. Om någon del av felinformationen måste returneras till programmet måste koden i CATCH blocket göra det med hjälp av mekanismer som SELECT resultatuppsättningar eller RAISERROR - PRINT instruktioner.

TRY...CATCH konstruktioner kan kapslas. Antingen ett TRY block eller ett CATCH block kan innehålla kapslade TRY...CATCH konstruktioner. Ett block kan till exempel CATCH innehålla en inbäddad TRY...CATCH konstruktion för att hantera fel som påträffas av CATCH koden.

Fel som påträffas i ett CATCH block behandlas som fel som genereras någon annanstans. Om blocket CATCH innehåller en kapslad TRY...CATCH konstruktion skickar eventuella fel i det kapslade TRY blocket kontrollen till det kapslade CATCH blocket. Om det inte finns någon kapslad TRY...CATCH konstruktion skickas felet tillbaka till anroparen.

TRY...CATCH konstruerar fånga ohanterade fel från lagrade procedurer eller utlösare som körs av koden i TRY blocket. Alternativt kan lagrade procedurer eller utlösare innehålla egna TRY...CATCH konstruktioner för att hantera fel som genereras av koden. När ett TRY block till exempel kör en lagrad procedur och ett fel inträffar i den lagrade proceduren kan felet hanteras på följande sätt:

  • Om den lagrade proceduren inte innehåller en egen TRY...CATCH konstruktion returnerar felet kontrollen till blocket CATCH som är associerat med TRY blocket som innehåller -instruktionen EXECUTE .

  • Om den lagrade proceduren innehåller en TRY...CATCH konstruktion överför felkontrollen till CATCH blocket i den lagrade proceduren. CATCH När blockkoden är klar skickas kontrollen tillbaka till -instruktionen omedelbart efter -instruktionen EXECUTE som anropade den lagrade proceduren.

GOTO -instruktioner kan inte användas för att ange ett TRY eller CATCH blockera. GOTO-instruktioner kan användas för att hoppa till en etikett i samma TRY eller CATCH blockera eller för att lämna en eller CATCH ett TRY block.

Konstruktionen TRY...CATCH kan inte användas i en användardefinierad funktion.

Hämta felinformation

I omfånget för ett CATCH block kan följande systemfunktioner användas för att hämta information om felet som orsakade CATCH att blocket kördes:

Function Description
ERROR_NUMBER Returnerar felets nummer.
ERROR_SEVERITY Returnerar allvarlighetsgraden.
ERROR_STATE Returnerar feltillståndsnumret.
ERROR_PROCEDURE Returnerar namnet på den lagrade proceduren eller utlösaren där felet inträffade.
ERROR_LINE Returnerar radnumret i den rutin som orsakade felet.
ERROR_MESSAGE Returnerar den fullständiga texten i felmeddelandet. Texten innehåller de värden som anges för eventuella substitutabellparametrar, till exempel längder, objektnamn eller tider.

Dessa funktioner returneras NULL om de anropas utanför blockets CATCH omfång. Felinformation kan hämtas med hjälp av dessa funktioner var som helst inom blockets CATCH omfång. Följande skript visar till exempel en lagrad procedur som innehåller felhanteringsfunktioner. I byggblocket CATCHTRY...CATCH anropas den lagrade proceduren och information om felet returneras.

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

Funktionerna ERROR_* fungerar också i ett CATCH block i en internt kompilerad lagrad procedur.

Fel som inte påverkas av ett TRY... CATCH-konstruktion

TRY...CATCH konstruktioner sväller inte följande villkor:

  • Varningar eller informationsmeddelanden som har en allvarlighetsgrad på 10 eller lägre.

  • Fel som har en allvarlighetsgrad på 20 eller högre som stoppar sql Server Database Engine-uppgiftsbearbetningen för sessionen. Om ett fel inträffar med allvarlighetsgraden 20 eller högre och databasanslutningen inte störs hanterar TRY...CATCH du felet.

  • Uppmärksamhet, till exempel begäranden om klientavbrott eller brutna klientanslutningar.

  • När en systemadministratör använder -instruktionen KILL för att avsluta sessionen.

Följande typer av fel hanteras inte av ett CATCH block när de inträffar på samma körningsnivå som konstruktionen TRY...CATCH :

  • Kompilera fel, till exempel syntaxfel, som förhindrar att en batch körs.

  • Fel som uppstår vid omkompilering på instruktionsnivå, till exempel fel vid matchning av objektnamn som uppstår efter kompilering på grund av uppskjuten namnmatchning.

  • Fel vid matchning av objektnamn

Dessa fel returneras till den nivå som körde batchen, den lagrade proceduren eller utlösaren.

Om ett fel uppstår under kompilering eller omkompilering på instruktionsnivå på en lägre körningsnivå (till exempel vid körning sp_executesql eller en användardefinierad lagrad procedur) inuti TRY blocket uppstår felet på en lägre nivå än konstruktionen TRY...CATCH och hanteras av det associerade CATCH blocket.

I följande exempel visas hur ett objektnamnsmatchningsfel som genereras av en SELECT -instruktion inte fångas av konstruktionen TRY...CATCH , utan fångas av CATCH blocket när samma SELECT -instruktion körs i en lagrad procedur.

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

Felet fångas inte och kontrollen skickas ut från konstruktionen TRY...CATCH till nästa högre nivå.

Om du kör -instruktionen SELECT i en lagrad procedur uppstår felet på en nivå som är lägre än TRY blocket. Felet hanteras av konstruktionen 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;

Icke-bindande transaktioner och XACT_STATE

Om ett fel som genereras i ett TRY block gör att tillståndet för den aktuella transaktionen ogiltigförklaras klassificeras transaktionen som en transaktion som inte kan tas emot. Ett fel som normalt avslutar en transaktion utanför ett TRY block gör att en transaktion går att komma åt när felet inträffar i ett TRY block. En transaktion som inte kan nås kan bara utföra läsåtgärder eller en ROLLBACK TRANSACTION. Transaktionen kan inte köra några Transact-SQL-instruktioner som skulle generera en skrivåtgärd eller en COMMIT TRANSACTION. Funktionen XACT_STATE returnerar ett värde för -1 om en transaktion har klassificerats som en transaktion som inte kan nås. När en batch är klar återställer databasmotorn alla aktiva transaktioner som inte kan nås. Om inget felmeddelande skickades när transaktionen övergick till ett tillstånd som inte kan komma i fråga skickas ett felmeddelande till klientprogrammet när batchen är klar. Detta indikerar att en transaktion som inte kan nås har identifierats och återställts.

Mer information om icke-bindande transaktioner och XACT_STATE funktionen finns i XACT_STATE.

Examples

A. Use TRY...CATCH

I följande exempel visas en SELECT instruktion som genererar ett divide-by-zero-fel. Felet gör att körningen hoppar till det associerade CATCH blocket.

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. Använd TRY... CATCH i en transaktion

I följande exempel visas hur ett TRY...CATCH block fungerar i en transaktion. Instruktionen TRY i blocket genererar ett fel om begränsningsöverträdelse.

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. Använd TRY... CATCH med XACT_STATE

I följande exempel visas hur du använder konstruktionen TRY...CATCH för att hantera fel som inträffar i en transaktion. Funktionen XACT_STATE avgör om transaktionen ska checkas in eller återställas. I det här exemplet SET XACT_ABORT är ON. Detta gör transaktionen okommentabel när begränsningsfelet inträffar.

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