TRY...CATCH (Transact-SQL)

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

Icona di collegamento a un argomento Convenzioni della sintassi Transact-SQL


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

sql_statement

Qualsiasi istruzione Transact-SQL.

statement_block

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

Un costrutto TRY…CATCH intercetta tutti gli errori di esecuzione con livello di gravità superiore a 10 che non determinano la chiusura della connessione al database.

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

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

Se non si verificano errori nel codice racchiuso in un blocco TRY, al termine dell'esecuzione dell'ultima istruzione nel blocco TRY il controllo passa all'istruzione immediatamente successiva all'istruzione END CATCH associata. Se si verifica un errore nel codice racchiuso in un blocco TRY, il controllo passa alla prima istruzione nel blocco CATCH associato. Se l'istruzione END CATCH è l'ultima istruzione in una stored procedure o un trigger, il controllo viene restituito all'istruzione che ha chiamato la stored procedure o attivato il trigger.

Al termine del codice nel blocco CATCH, il controllo passa all'istruzione immediatamente successiva all'istruzione END CATCH. Gli errori intercettati da un blocco CATCH non vengono restituiti all'applicazione chiamante. Se qualsiasi parte delle informazioni sugli errori deve essere restituita all'applicazione, il codice nel blocco CATCH deve utilizzare a tale scopo meccanismi come i set di risultati SELECT o le istruzioni RAISERROR e PRINT. Per ulteriori informazioni sull'utilizzo di RAISERROR con TRY…CATCH, vedere Utilizzo di TRY...CATCH in Transact-SQL.

I costrutti TRY…CATCH possono essere nidificati. I costrutti TRY…CATCH nidificati possono essere contenuti in un blocco TRY oppure in un blocco CATCH. Ad esempio, un blocco CATCH può contenere un costrutto TRY…CATCH incorporato per gestire gli errori rilevati dal codice CATCH.

Gli errori rilevati in un blocco CATCH vengono considerati come gli errori generati in qualsiasi altra posizione. Se il blocco CATCH contiene un costrutto TRY…CATCH nidificato, qualsiasi errore nel blocco TRY nidificato passerà il controllo al blocco CATCH nidificato. Se non esiste un costrutto TRY…CATCH nidificato, l'errore ritorna al chiamante.

I costrutti TRY…CATCH rilevano gli errori non gestiti dalle stored procedure o dai trigger eseguiti dal codice in un blocco TRY. In alternativa, le stored procedure o i trigger possono contenere i propri costrutti TRY…CATCH per gestire gli errori generati dal proprio codice. Ad esempio, quando un blocco TRY 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 include uno specifico costrutto TRY…CATCH, l'errore restituisce il controllo al blocco CATCH associato al blocco TRY contenente l'istruzione EXECUTE.

  • Se la stored procedure include un costrutto TRY…CATCH, l'errore trasferisce il controllo al blocco CATCH nella stored procedure. Al termine del codice del blocco CATCH, il controllo viene restituito all'istruzione immediatamente successiva all'istruzione EXECUTE che ha chiamato la stored procedure.

Le istruzioni GOTO non possono essere utilizzate per immettere un blocco TRY o CATCH. Le istruzioni GOTO possono essere utilizzate per passare a un'etichetta all'interno dello stesso blocco TRY o CATCH oppure per uscire da un blocco TRY o CATCH.

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

Recupero delle informazioni sugli errori

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

  • ERROR_NUMBER() restituisce il numero dell'errore.

  • ERROR_SEVERITY() restituisce la gravità.

  • ERROR_STATE() restituisce il numero di contesto 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 per ogni parametro sostituibile, ad esempio le lunghezze, i nomi degli oggetti o il numero di occorrenze.

Queste funzioni restituiscono NULL se vengono chiamate all'esterno dell'ambito del blocco CATCH. È possibile recuperare informazioni sugli errori utilizzando queste funzioni in qualsiasi posizione all'interno dell'ambito del blocco CATCH. 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.

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

Errori su cui il costrutto TRY…CATCH non ha alcun effetto

I costrutti TRY…CATCH non intercettano 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à di Motore di database di SQL Server per la sessione. Se si verifica un errore con livello di gravità maggiore o uguale a 20 e la connessione al database non viene interrotta, l'errore verrà gestito da TRY…CATCH.

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

  • Quando la sessione viene terminata da un amministratore di sistema tramite l'istruzione KILL.

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

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

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

In caso di errore durante la compilazione o durante la ricompilazione a livello di istruzione a un livello di esecuzione inferiore (ad esempio, durante l'esecuzione di sp_executesql o di una stored procedure definita dall'utente) all'interno del blocco TRY, l'errore si verifica a un livello inferiore rispetto al costrutto TRY…CATCH e verrà gestito dal blocco CATCH associato. Per ulteriori informazioni, vedere Utilizzo di TRY...CATCH in Transact-SQL.

Nell'esempio seguente viene illustrato come un errore di risoluzione dei nomi degli oggetti generato da un'istruzione SELECT non venga intercettato dal costrutto TRY…CATCH, ma venga intercettato dal blocco CATCH quando la stessa istruzione SELECT viene eseguita all'interno di una stored procedure.

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

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

Eseguendo l'istruzione SELECT all'interno di una stored procedure, l'errore si verificherà a un livello inferiore rispetto al blocco TRY. L'errore verrà gestito dal costrutto 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;
  • Per ulteriori informazioni sui batch, vedere Batch.

Transazioni bloccate e XACT_STATE

Se un errore generato in un blocco TRY invalida lo stato della transazione corrente, la transazione viene classificata come transazione bloccata. Un errore che normalmente termina una transazione all'esterno di un blocco TRY causa il passaggio della transazione a uno stato di transazione bloccata quando si verifica all'interno di un blocco TRY. Una transazione bloccata può eseguire soltanto le operazioni di lettura o ROLLBACK TRANSACTION. La transazione non può eseguire istruzioni Transact-SQL che generano una operazione di scrittura o COMMIT TRANSACTION. La funzione XACT_STATE restituisce un valore -1 se una transazione è stata classificata come transazione bloccata. Al termine di un batch, Motore di database esegue automaticamente il rollback di qualsiasi transazione bloccata attiva. Se in occasione del passaggio della transazione a uno stato di transazione bloccata non sono stati inviati messaggi di errore, al termine del batch verrà inviato un messaggio di errore all'applicazione client. Viene così indicato che è stata rilevata una transazione bloccata e ne è stato eseguito il rollback.

Per ulteriori informazioni sulle transazioni bloccate e la funzione XACT_STATE, vedere Utilizzo di TRY...CATCH in Transact-SQL e XACT_STATE (Transact-SQL).

A. Utilizzo di 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.

USE AdventureWorks2008R2;
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. Utilizzo di 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.

USE AdventureWorks2008R2;
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. Utilizzo di TRY…CATCH con XACT_STATE

Nell'esempio seguente viene illustrato come utilizzare il costrutto TRY…CATCH per gestire gli errori che ci 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.

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

Aggiunte alla community

AGGIUNGI
Mostra: