Usando a função @@ERROR

A função de sistema @@ERROR retorna 0 se a última instrução Transact-SQL foi executada com êxito; se a instrução gerar um erro, @@ERROR retornará o número do erro. O valor da função @@ERROR altera a conclusão de cada instrução Transact-SQL.

Devido ao fato da função @@ERROR adquirir um valor novo toda vez que uma instrução Transact-SQL é concluída, o processo da função @@ERROR ocorre em uma das duas maneiras:

  • Teste ou use a função @@ERROR imediatamente depois da instrução Transact-SQL.

  • Salve a função @@ERROR em uma variável inteira imediatamente após a conclusão da instrução Transact-SQL. O valor da variável pode ser usado depois.

Se a instrução que gera o erro não estiver no bloco TRY de uma construção TRY...CATCH, a função @@ERROR deve ser testada ou usada na instrução imediatamente após a instrução que gerou o erro. Se a instrução que gera o erro estiver em um bloco TRY, a função @@ERROR deve ser testada ou usada na primeira instrução do bloco CATCH associado. No escopo de um bloco CATCH, a função ERROR_NUMBER pode ser usada para recuperar o mesmo número de erro registrado pela função @@ERROR. A função ERROR_NUMBER tem a vantagem de estar disponível para todas as instruções no escopo do bloco CATCH, enquanto que a função @@ERROR é redefinida pela primeira instrução do bloco CATCH.

Instruções condicionais, como a instrução IF, redefinem a função @@ERROR. Caso a função @@ERROR seja mencionada em uma instrução IF, as referências à função @@ERROR nos blocos IF ou ELSE não recuperarão as informações da função @@ERROR. No exemplo a seguir, a função @@ERROR é redefinida por IF e não retorna o número do erro quando mencionada na instrução PRINT.

DECLARE @ErrorVar INT

RAISERROR(N'Message', 16, 1);
IF @@ERROR <> 0
    -- This PRINT statement prints 'Error = 0' because
    -- @@ERROR is reset in the IF statement above.
    PRINT N'Error = ' + CAST(@@ERROR AS NVARCHAR(8));
GO

O exemplo a seguir retorna os resultados esperados.

DECLARE @ErrorVar INT

RAISERROR(N'Message', 16, 1);
-- Save the error number before @@ERROR is reset by
-- the IF statement.
SET @ErrorVar = @@ERROR
IF @ErrorVar <> 0
-- This PRINT statement correctly prints 'Error = 50000'.
    PRINT N'Error = ' + CAST(@ErrorVar AS NVARCHAR(8));
GO

Caso queira mencionar a funções @@ERROR e @@ROWCOUNT depois de executar uma instrução, mencione-as na mesma instrução. Ambas as funções @@ERROR e @@ROWCOUNT são redefinidas com cada instrução Transact-SQL; portanto, ambas devem ser mencionadas na mesma instrução imediatamente após uma ter sido testada. No exemplo a seguir, a função @@ROWCOUNT será sempre 0 porque não é mencionada até que seja redefinida pela primeira instrução PRINT.

USE AdventureWorks2008R2;
GO
DELETE FROM HumanResources.JobCandidate
    WHERE JobCandidateID = 13;
-- This PRINT would successfully capture any error number.
PRINT N'Error = ' + CAST(@@ERROR AS NVARCHAR(8));
-- This PRINT will always print 'Rows Deleted = 0 because
-- the previous PRINT statement set @@ROWCOUNT to 0.
PRINT N'Rows Deleted = ' + CAST(@@ROWCOUNT AS NVARCHAR(8));
GO

O exemplo a seguir retorna os resultados esperados.

USE AdventureWorks2008R2;
GO
DECLARE @ErrorVar INT;
DECLARE @RowCountVar INT;

DELETE FROM HumanResources.JobCandidate
  WHERE JobCandidateID = 13;
-- Save @@ERROR and @@ROWCOUNT while they are both
-- still valid.
SELECT @ErrorVar = @@ERROR,
    @RowCountVar = @@ROWCOUNT;
IF (@ErrorVar <> 0)
    PRINT N'Error = ' + CAST(@ErrorVar AS NVARCHAR(8));
PRINT N'Rows Deleted = ' + CAST(@RowCountVar AS NVARCHAR(8));
GO

A função @@ERROR é gerada apenas para erros e não para avisos; lotes, procedimentos armazenados e gatilhos não podem usar a função @@ERROR para detectar qualquer aviso que tenha ocorrido.

Um uso comum da função @@ERROR na SQL Server 2000 e anterior é de indicar o sucesso ou falha de um procedimento armazenado. Uma variável inteira é inicializada em 0. Depois que cada instrução Transact-SQL for concluída, a função @@ERROR será testada para dar 0, mas se não der 0, será armazenada em uma variável. O procedimento então retorna a variável na instrução RETURN. Se nenhuma das instruções Transact-SQL no procedimento tiver um erro, a variável permanecerá em 0. Se uma ou mais instruções geraram um erro, a variável manterá o último número do erro. O exemplo a seguir mostra um procedimento armazenado simples com esta lógica.

USE AdventureWorks2008R2;
GO
IF EXISTS(SELECT name FROM sys.objects
          WHERE name = N'SampleProcedure')
    DROP PROCEDURE SampleProcedure;
GO
-- Create a procedure that takes one input parameter
-- and returns one output parameter and a return code.
CREATE PROCEDURE SampleProcedure @EmployeeIDParm INT,
    @MaxVacation INT OUTPUT
AS

    -- Declare and initialize a variable to hold @@ERROR.
    DECLARE @ErrorSave1 INT, @ErrorSave2 INT;
    SET @ErrorSave1 = 0;

    -- Do a SELECT using the input parameter.
    SELECT LoginID, NationalIDNumber, JobTitle
        FROM HumanResources.Employee
        WHERE BusinessEntityID = @EmployeeIDParm;

    -- Save @@ERROR value in first local variable.
    SET @ErrorSave1 = @@ERROR;

    -- Set a value in the output parameter.
    SELECT @MaxVacation = MAX(VacationHours)
        FROM HumanResources.Employee;

    -- Save @@ERROR value in second local variable. 
    SET @ErrorSave2 = @@ERROR;
    -- If second test variable contains non-zero value, 
    -- overwrite value in first local variable.
    IF (@ErrorSave2 <> 0) SET @ErrorSave1 = @ErrorSave2;

    -- Returns 0 if neither SELECT statement had
    -- an error; otherwise, returns the last error.
    RETURN @ErrorSave1;
GO
    
DECLARE @OutputParm INT;
DECLARE @ReturnCode INT;

EXEC @ReturnCode = SampleProcedure 13, @OutputParm OUTPUT;

PRINT N'OutputParm = ' + CAST(@OutputParm AS NVARCHAR(20));
PRINT N'ReturnCode = ' + CAST(@ReturnCode AS NVARCHAR(20));
GO

@@ERROR vs. TRY...CATCH

O uso da função @@ERROR como o principal meio de detectar erros leva a um estilo muito diferente de código de tratamento de erro daquele usado nas construções TRY...CATCH.

  • A função @@ERROR tem que ser testada ou salva depois de cada instrução Transact-SQL porque um desenvolvedor não pode prever com antecedência qual instrução poderá gerar um erro. Isso dobra o número de instruções Transact-SQL que devem ser codificadas para implementar uma lógica determinada.

  • As construções TRY....CATCH são muito mais simples. Um bloco de instruções Transact-SQL é associado pelas instruções BEGIN TRY e END TRY e um bloco CATCH é gravado para controlar os erros que possam ser gerados pelo bloco de instruções.

Fora de um bloco CATCH, a função @@ERROR é a única parte de um erro Mecanismo de Banco de Dados disponível no lote, no procedimento armazenado ou no gatilho que gerou o erro. Todas as outras partes do erro, como severidade, estado e texto da mensagem contendo cadeias de caracteres de substituição (nomes de objetos, por exemplo) são retornados apenas para o aplicativo no qual possam ser processadas usando os mecanismos de tratamento de erros API. Se o erro invocar um bloco CATCH, as funções de sistema ERROR_LINE, ERROR_MESSAGE, ERROR_PROCEDURE, ERROR_NUMBER, ERROR_SEVERITY e ERROR_STATE poderão ser usadas.