Partilhar via


TRY...CATCH (Transact-SQL)

Implementa tratamento de erros para Transact-SQL semelhante ao tratamento de exceções nas linguagens Microsoft Visual C# e Microsoft Visual C++. Um grupo de instruções Transact-SQL pode ser incluído em um bloco TRY. Se ocorrer um erro no bloco TRY, o controle passará para outro grupo de instruções que está incluído em um bloco CATCH.

Ícone de vínculo de tópicoConvenções de sintaxe Transact-SQL

Sintaxe

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

Argumentos

  • sql_statement
    É qualquer instrução Transact-SQL.

  • statement_block
    Qualquer grupo de instruções Transact-SQL em um lote ou incluso em um bloco BEGIN…END.

Comentários

Uma construção TRY...CATCH captura todos os erros de execução com severidade maior que 10 e que não fecham a conexão do banco de dados.

Um bloco TRY deve ser seguido imediatamente por um bloco CATCH associado. A inclusão de qualquer outra instrução entre as instruções END TRY e BEGIN CATCH gera um erro de sintaxe.

Uma construção TRY…CATCH não pode abranger vários lotes. Uma construção TRY…CATCH não pode abranger vários blocos de instruções Transact-SQL. Por exemplo, uma construção TRY…CATCH não pode abranger dois blocos BEGIN…END de instruções Transact-SQL e não pode abranger uma construção IF…ELSE.

Se não houver erros no código incluído em um bloco TRY, quando a execução da última instrução no bloco TRY for concluída, o controle passará para a instrução imediatamente posterior à instrução END CATCH associada. Se houver um erro no código incluído em um bloco TRY, o controle passará para a primeira instrução do bloco CATCH associado. Se a instrução END CATCH for a última instrução de um procedimento armazenado ou gatilho, o controle voltará para a instrução que chamou o procedimento armazenado ou acionou o gatilho.

Quando o código no bloco CATCH for concluído, o controle passará para a instrução imediatamente posterior à instrução END CATCH. Os erros interceptados por um bloco CATCH não são retornados ao aplicativo que o chamou. Se qualquer parte das informações de erro precisar ser retornada ao aplicativo, o código no bloco CATCH deverá fazê-lo usando mecanismos como conjuntos de resultados SELECT ou as instruções RAISERROR e PRINT. Para obter mais informações sobre como usar RAISERROR com TRY…CATCH, consulte Usando TRY...CATCH na Transact-SQL.

As construções TRY...CATCH podem ser aninhadas. Um bloco TRY ou um bloco CATCH pode conter construções TRY…CATCH aninhadas. Por exemplo, um bloco CATCH pode conter uma construção TRY…CATCH incorporada para tratar erros encontrados pelo código de CATCH.

Os erros encontrados em um bloco CATCH são tratados como erros gerados em qualquer outro lugar. Se o bloco CATCH contiver uma construção TRY…CATCH aninhada, qualquer erro no bloco TRY aninhado passará o controle para o bloco CATCH aninhado. Se não houver nenhuma construção TRY…CATCH aninhada, o erro voltará para o chamador.

As construções TRY…CATCH capturam erros não tratados de procedimentos armazenados ou gatilhos executados pelo código do bloco TRY. Como alternativa, os procedimentos armazenados ou os gatilhos podem conter suas próprias construções TRY…CATCH para tratar os erros gerados por seu código. Por exemplo, quando um bloco TRY executa um procedimento armazenado e ocorre um erro no procedimento, o erro poderá ser tratado das seguintes maneiras:

  • Se o procedimento armazenado não contiver sua própria construção TRY…CATCH, o erro retornará o controle para o bloco CATCH associado ao bloco TRY que contém a instrução EXECUTE.

  • Se o procedimento armazenado contiver uma construção TRY…CATCH, o erro transferirá o controle para o bloco CATCH do procedimento armazenado. Quando o código do bloco CATCH for concluído, o controle voltará para a instrução imediatamente posterior à instrução EXECUTE que chamou o procedimento armazenado.

As instruções GOTO não podem ser usadas para inserir um bloco TRY ou CATCH. As instruções GOTO podem ser usadas para saltar para um rótulo dentro do mesmo bloco TRY ou CATCH ou para sair de um bloco TRY ou CATCH.

A construção TRY…CATCH não pode ser usada em uma função definida pelo usuário.

Recuperando informações de erro

No escopo de um bloco CATCH, as seguintes funções de sistema podem ser usadas para obter informações sobre o erro que causou a execução do bloco CATCH.

  • ERROR_NUMBER() retorna o número do erro.

  • ERROR_SEVERITY() retorna a severidade.

  • ERROR_STATE() retorna o número do estado do erro.

  • ERROR_PROCEDURE() retorna o nome do procedimento armazenado ou do gatilho no qual ocorreu o erro.

  • ERROR_LINE () retorna o número de linha dentro da rotina que causou o erro.

  • ERROR_MESSAGE () retorna o texto completo da mensagem de erro. O texto inclui os valores fornecidos para quaisquer parâmetros substituíveis, como comprimentos, nomes de objeto ou horas.

Essas funções retornarão NULL se forem chamadas fora do escopo do bloco CATCH. As informações de erro podem ser recuperadas com o uso dessas funções em qualquer lugar no escopo do bloco CATCH. Por exemplo, o script a seguir mostra um procedimento armazenado que contém funções de tratamento de erros. No bloco CATCH de uma construção TRY…CATCH, o procedimento armazenado é chamado e as informações sobre o erro são retornadas.

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;

Erros não afetados por uma construção TRY…CATCH

As construções TRY…CATCH não interceptam as seguintes condições:

  • Avisos ou mensagens informativas que têm uma severidade 10 ou menor.

  • Erros que têm uma severidade 20 ou maior, que param o processamento de tarefa do Mecanismo de banco de dados do SQL Server para a sessão. Se ocorrer um erro com severidade 20 ou maior e a conexão com o banco de dados não for interrompida, TRY…CATCH tratará o erro.

  • Atenções, como solicitações da interrupção de cliente ou conexões de cliente desfeitas.

  • Quando a sessão for finalizada por um administrador de sistema com o uso da instrução KILL.

Os seguintes tipos de erros não são tratados por um bloco CATCH quando ocorrerem no mesmo nível de execução que a construção TRY…CATCH:

  • Erros de compilação, como erros de sintaxe, que impeçam a execução de um lote.

  • Erros que ocorrem durante a recompilação em nível de instrução, como os erros de resolução do nome de objeto que ocorrem após a compilação, devido à resolução adiada do nome.

Esses erros são retornados ao nível que executou o lote, o procedimento armazenado ou o gatilho.

Se ocorrer um erro durante a compilação ou a recompilação no nível da instrução em um nível de execução inferior (por exemplo, ao executar sp_executesql ou um procedimento armazenado definido pelo usuário) dentro do bloco TRY, o erro ocorrerá em um nível inferior ao da construção TRY…CATCH e será tratado pelo bloco CATCH associado. Para obter mais informações, consulte Usando TRY...CATCH na Transact-SQL.

O exemplo a seguir mostra como um erro de resolução de nome de objeto gerado por uma instrução SELECT não é capturado pela construção TRY…CATCH, mas é capturado pelo bloco CATCH quando a mesma instrução SELECT é executada dentro de um procedimento armazenado.

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

O erro não é capturado e o controle é transmitido para fora da construção TRY…CATCH para o próximo nível mais alto.

A execução da instrução SELECT dentro de um procedimento armazenado fará com que o erro ocorra em um nível inferior ao do bloco TRY. O erro será tratado pela construção 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;
  • Para obter mais informações sobre lotes, consulte Lotes.

Transações não confirmáveis e XACT_STATE

Se um erro gerado em um bloco TRY fizer com que o estado da transação atual seja invalidado, a transação será classificada como não confirmável. Um erro que normalmente finaliza uma transação fora de um bloco TRY faz com que uma transação entre em um estado não confirmável quando o erro ocorre dentro de um bloco TRY. Uma transação não confirmável só pode executar operações de leitura ou uma ROLLBACK TRANSACTION. A transação não pode executar nenhuma instrução Transact-SQL que geraria uma operação de gravação ou uma COMMIT TRANSACTION. A função XACT_STATE retornará o valor -1 se uma transação foi classificada como não confirmável. Quando um lote é concluído, o Mecanismo de Banco de Dados reverte quaisquer transações ativas não confirmáveis. Se nenhuma mensagem de erro foi enviada quando a transação entrou em um estado não confirmável, quando o lote terminar, uma mensagem de erro será enviada ao aplicativo cliente. Isso indica que uma transação não confirmável foi detectada e revertida.

Para obter mais informações sobre transações não confirmáveis e a função XACT_STATE, consulte Usando TRY...CATCH na Transact-SQL e XACT_STATE (Transact-SQL).

Exemplos

A. Usando TRY…CATCH

O exemplo a seguir mostra uma instrução SELECT que gerará um erro de divisão por zero. O erro faz com que a execução salte para o bloco CATCH associado.

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. Usando TRY…CATCH em uma transação

O exemplo a seguir mostra como um bloco TRY…CATCH funciona dentro de uma transação. A instrução dentro do bloco TRY gera um erro de violação de restrição.

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. Usando TRY…CATCH com XACT_STATE

O exemplo a seguir mostra como usar a construção TRY…CATCH para tratar erros que ocorram dentro de uma transação. A função XACT_STATE determina se a transação deve ser confirmada ou revertida. Neste exemplo, SET XACT_ABORT é ON. Isso torna a transação não confirmável quando o erro de violação de restrição ocorrer.

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