Condividi tramite


TRY...CATCH (Transact-SQL)

Si applica a: SQL Server database SQL di Azure Istanza gestita di SQL di Azure endpoint di analisi SQL di Azure Synapse Analytics Platform System (PDW) in Microsoft Fabric Warehouse nel database SQL di Microsoft Fabric in Microsoft Fabric

Implementa la gestione degli errori per Transact-SQL simile alla gestione delle eccezioni nei linguaggi C# e Visual C++. Un gruppo di istruzioni Transact-SQL può essere racchiuso in un TRY blocco. Se si verifica un errore nel blocco, il TRY controllo viene in genere passato a un altro gruppo di istruzioni racchiuso in un CATCH blocco.

Convenzioni relative alla sintassi Transact-SQL

Sintassi

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

Argomenti

sql_statement

Qualsiasi istruzione Transact-SQL.

statement_block

Qualsiasi gruppo di istruzioni Transact-SQL in un batch o racchiuso in un BEGIN...END blocco.

Osservazioni:

Un TRY...CATCH costrutto rileva tutti gli errori di esecuzione con gravità superiore a 10 che non chiudono la connessione al database.

Un TRY blocco deve essere seguito immediatamente da un blocco associato CATCH . L'inclusione di qualsiasi altra istruzione tra le END TRY istruzioni e BEGIN CATCH genera un errore di sintassi.

Un TRY...CATCH costrutto non può estendersi su più batch. Un TRY...CATCH costrutto non può estendersi su più blocchi di istruzioni Transact-SQL. Ad esempio, un TRY...CATCH costrutto non può estendersi su due BEGIN...END blocchi di istruzioni Transact-SQL e non può estendersi su un IF...ELSE costrutto.

Se non sono presenti errori nel codice racchiuso in un TRY blocco, al termine dell'ultima istruzione nel TRY blocco, il controllo passa all'istruzione immediatamente dopo l'istruzione associata END CATCH .

Se si verifica un errore nel codice racchiuso in un TRY blocco, il controllo passa alla prima istruzione nel blocco associato CATCH . Al termine del CATCH codice nel blocco, il controllo passa all'istruzione immediatamente dopo l'istruzione END CATCH .

Nota

Se l'istruzione END CATCH è l'ultima istruzione in una stored procedure o un trigger, il controllo viene passato all'istruzione che ha chiamato la stored procedure o attivato il trigger.

Gli errori intrappolati da un CATCH blocco non vengono restituiti all'applicazione chiamante. Se una parte delle informazioni sull'errore deve essere restituita all'applicazione, il codice nel CATCH blocco deve farlo usando meccanismi quali SELECT set di risultati o RAISERROR istruzioni e PRINT .

TRY...CATCH i costrutti possono essere annidati. Un TRY blocco o un CATCH blocco può contenere costrutti annidati TRY...CATCH . Ad esempio, un CATCH blocco può contenere un costrutto incorporato TRY...CATCH per gestire gli errori rilevati dal CATCH codice.

Gli errori rilevati in un CATCH blocco vengono considerati come errori generati in qualsiasi altra posizione. Se il CATCH blocco contiene un costrutto annidato, qualsiasi errore nel blocco annidato TRY...CATCH TRY passa il controllo al blocco annidato CATCH . Se non è presente alcun costrutto annidato, l'errore viene restituito TRY...CATCH al chiamante.

TRY...CATCH costruisce rileva errori non gestiti da stored procedure o trigger eseguiti dal codice nel TRY blocco. In alternativa, le stored procedure o i trigger possono contenere costrutti personalizzati TRY...CATCH per gestire gli errori generati dal codice. Ad esempio, quando un TRY blocco esegue una stored procedure e si verifica un errore nella stored procedure, l'errore può essere gestito nei modi seguenti:

  • Se la stored procedure non contiene il proprio TRY...CATCH costrutto, l'errore restituisce il controllo al CATCH blocco associato al TRY blocco che contiene l'istruzione EXECUTE .

  • Se la stored procedure contiene un TRY...CATCH costrutto, il controllo viene trasferita al CATCH blocco nella stored procedure. Al termine del codice del blocco, il CATCH controllo viene passato all'istruzione immediatamente dopo l'istruzione EXECUTE che ha chiamato la stored procedure.

GOTO Le istruzioni non possono essere usate per immettere un TRY blocco o CATCH . GOTO Le istruzioni possono essere usate per passare a un'etichetta all'interno dello stesso TRY blocco o CATCH per lasciare un TRY blocco o CATCH .

Il TRY...CATCH costrutto non può essere usato in una funzione definita dall'utente.

Recuperare le informazioni sull'errore

Nell'ambito di un CATCH blocco, è possibile usare le funzioni di sistema seguenti per ottenere informazioni sull'errore che ha causato l'esecuzione del CATCH blocco:

Funzione Descrizione
ERROR_NUMBER Restituisce il numero dell'errore.
ERROR_SEVERITY Restituisce la gravità.
ERROR_STATE Restituisce il numero di stato dell'errore.
ERROR_PROCEDURE Restituisce il nome della stored procedure o del trigger in cui si è verificato l'errore.
ERROR_LINE Restituisce il numero di riga all'interno della routine che ha causato l'errore.
ERROR_MESSAGE Restituisce il testo completo del messaggio di errore. Il testo include i valori forniti da qualsiasi parametro sostituibile, ad esempio lunghezze, nomi di oggetti oppure orari.

Queste funzioni restituiscono NULL se vengono chiamate all'esterno dell'ambito del CATCH blocco. Le informazioni sugli errori possono essere recuperate usando queste funzioni da qualsiasi punto all'interno dell'ambito del CATCH blocco. Nello script seguente, ad esempio, viene illustrata una stored procedure contenente funzioni di gestione degli errori. Nel blocco CATCH di un costrutto TRY...CATCH viene chiamata la stored procedure e vengono restituite informazioni sull'errore.

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

Le ERROR_* funzioni funzionano anche in un CATCH blocco all'interno di una stored procedure compilata in modo nativo.

Errori non interessati da un tentativo... Costrutto CATCH

TRY...CATCH i costrutti non intercettare le condizioni seguenti:

  • Avvisi o messaggi informativi con livello di gravità minore o uguale a 10.

  • Errori con livello di gravità maggiore o uguale a 20 che determinano l'arresto dell'elaborazione dell'attività del motore di database di SQL Server per la sessione. Se si verifica un errore con gravità pari o superiore a 20 e la connessione al database non viene interrotta, TRY...CATCH gestisce l'errore.

  • Situazioni di attenzione, richieste di interruzione dei client o interruzione delle connessioni client.

  • Quando un amministratore di sistema usa l'istruzione KILL per terminare la sessione.

I tipi di errori seguenti non vengono gestiti da un CATCH blocco quando si verificano allo stesso livello di esecuzione del TRY...CATCH costrutto:

  • Errori di compilazione, ad esempio errori di sintassi, che impediscono l'esecuzione di un batch.

  • Errori che si verificano durante la ricompilazione a livello di istruzione, ad esempio errori di risoluzione dei nomi degli oggetti che si verificano dopo la compilazione a causa della risoluzione dei nomi posticipata.

  • Errori di risoluzione del nome oggetto

Questi errori sono restituiti al livello che ha eseguito il batch, la stored procedure o il trigger.

Se si verifica un errore durante la compilazione o la ricompilazione a livello di istruzione a un livello di esecuzione inferiore (ad esempio, durante l'esecuzione sp_executesql o una stored procedure definita dall'utente) all'interno del TRY blocco, l'errore si verifica a un livello inferiore rispetto al TRY...CATCH costrutto e verrà gestito dal blocco associato CATCH .

Nell'esempio seguente viene illustrato come un errore di risoluzione dei nomi di oggetto generato da un'istruzione SELECT non venga intercettato dal TRY...CATCH costrutto, ma viene intercettato dal CATCH blocco quando la stessa SELECT istruzione viene eseguita all'interno di una stored 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

L'errore non viene intercettato e il controllo passa dal TRY...CATCH costrutto al livello superiore successivo.

Se si esegue l'istruzione SELECT all'interno di una stored procedure, l'errore si verifica a un livello inferiore al TRY blocco. L'errore viene gestito dal TRY...CATCH costrutto .

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

Transazioni e XACT_STATE non modificabili

Se un errore generato in un TRY blocco causa l'invalidazione dello stato della transazione corrente, la transazione viene classificata come transazione non modificabile. Un errore che in genere termina una transazione all'esterno di un TRY blocco fa sì che una transazione entri in uno stato non modificabile quando l'errore si verifica all'interno di un TRY blocco. Una transazione non modificabile può eseguire solo operazioni di lettura o .ROLLBACK TRANSACTION La transazione non può eseguire istruzioni Transact-SQL che generano un'operazione di scrittura o .COMMIT TRANSACTION La XACT_STATE funzione restituisce un valore di -1 se una transazione è stata classificata come transazione non modificabile. Al termine di un batch, il motore di database esegue automaticamente il rollback di qualsiasi transazione attiva di cui non è possibile eseguire il commit. Se non viene inviato alcun messaggio di errore quando la transazione ha immesso uno stato non modificabile, al termine del batch viene inviato un messaggio di errore all'applicazione client. Viene così indicato che è stata rilevata una transazione bloccata e ne è stato eseguito il rollback.

Per altre informazioni sulle transazioni non committable e sulla XACT_STATE funzione , vedere XACT_STATE.

Esempi

R. Usare TRY...CATCH

Nell'esempio seguente viene illustrata un'istruzione SELECT che genera un errore di divisione per zero. L'errore determina il passaggio dell'esecuzione al blocco CATCH associato.

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. Usare TRY... CATCH in una transazione

Nell'esempio seguente viene illustrato il funzionamento di un blocco TRY...CATCH all'interno di una transazione. L'istruzione all'interno del blocco TRY genera un errore di violazione di vincolo.

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. Usare TRY... CATCH con XACT_STATE

Nell'esempio seguente viene illustrato come utilizzare il costrutto TRY...CATCH per gestire gli errori che si verificano all'interno di una transazione. La funzione XACT_STATE determina se è necessario eseguire il commit o il rollback della transazione. In this example, l'evento SET XACT_ABORT è ON. Rende pertanto bloccata la transazione quando si verifica l'errore di violazione di vincolo.

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