Utilisation de @@ERROR

La fonction système @@ERROR renvoie 0 si la dernière instruction Transact-SQL a été exécutée avec succès ; dans le cas contraire, @@ERROR renvoie le numéro de l'erreur. La valeur de @@ERROR change à la fin de l'exécution de chaque instruction Transact-SQL.

Étant donné que la valeur de @@ERROR change lorsque chaque instruction Transact-SQL est exécutée, utilisez @@ERROR de l'une des deux façons suivantes :

  • Testez ou utilisez @@ERROR immédiatement après l'instruction Transact-SQL.

  • Enregistrez @@ERROR dans une variable de type entier immédiatement après l'exécution de l'instruction Transact-SQL. La valeur de la variable peut être utilisée ultérieurement.

Si l'instruction qui génère l'erreur ne se trouve pas dans le bloc TRY d'une construction TRY…CATCH, @@ERROR doit être testée ou utilisée dans l'instruction qui suit immédiatement l'instruction qui a généré l'erreur. Si l'instruction qui génère l'erreur se trouve dans le bloc TRY, @@ERROR peut être testée ou utilisée dans la première instruction du bloc CATCH associé. Dans l'étendue d'un bloc CATCH, la fonction ERROR_NUMBER peut être employée pour récupérer le même numéro d'erreur que celui rapporté par @@ERROR. ERROR_NUMBER présente l'avantage d'être disponible pour toutes les instructions dans l'étendue du bloc CATCH, alors que @@ERROR est réinitialisée par la première instruction de ce dernier.

Les instructions conditionnelles, telles que IF, réinitialisent @@ERROR. Si vous référencez @@ERROR dans une instruction IF, les références à @@ERROR dans le bloc IF ou ELSE ne récupèrent pas les informations de @@ERROR. Dans l'exemple suivant, @@ERROR est réinitialisée par IF et ne renvoie pas le numéro d'erreur lorsqu'elle est référencée dans l'instruction 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

L'exemple suivant renvoie les résultats attendus.

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

Si vous voulez référencer @@ERROR et @@ROWCOUNT après l'exécution d'une instruction, elles doivent toutes deux être référencées dans la même instruction ; en effet, elles sont réinitialisées avec chaque instruction Transact-SQL et doivent donc être référencées dans la même instruction, immédiatement après celle qui est testée. Dans l'exemple ci-dessous, @@ROWCOUNT a toujours pour valeur 0 car elle n'est pas référencée tant qu'elle n'a pas été réinitialisée par la première instruction 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

L'exemple suivant renvoie les résultats attendus.

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

@@ERROR est déclenché seulement pour les erreurs, mais pas pour les avertissements ; les traitements, les procédures stockées et les déclencheurs ne peuvent pas utiliser @@ERROR pour détecter les avertissements intervenus.

@@ERROR est le plus souvent utilisé dans SQL Server 2000 et les versions précédentes pour indiquer si une procédure stockée a été exécutée avec succès ou non. Une variable de type entier est initialisée à 0. Lorsque chacune des instructions Transact-SQL a été exécutée, la valeur de @@ERROR est testée ; si elle est différente de 0, elle est stockée dans la variable. La procédure renvoie ensuite la variable avec l'instruction RETURN. Si aucune des instructions Transact-SQL dans la procédure ne comportait d'erreur, le variable reste à 0. Si une ou plusieurs instructions ont généré une erreur, la variable maintient le dernier numéro d'erreur. Voici une procédure stockée simple appliquant cette logique :

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 et TRY...CATCH

L'utilisation de @@ERROR en tant que moyen principal pour détecter des erreurs génère un type très différent de code de gestion d'erreur que celui employé par les constructions TRY…CATCH.

  • @@ERROR doit être testée ou enregistrée après chaque instruction Transact-SQL car le développeur ne peut prévoir l'instruction qui risque de générer une erreur. Le nombre d'instructions Transact-SQL à coder pour implémenter une logique donnée est doublé.

  • Les constructions TRY…CATCH sont beaucoup plus simples. Un bloc d'instructions Transact-SQL est lié par les instructions BEGIN TRY et END TRY, puis un seul bloc CATCH est inséré pour gérer les erreurs susceptibles d'être générées par ce bloc d'instructions.

À l'extérieur d'un bloc CATCH, @@ERROR est la seule partie d’une erreur du Moteur de base de données disponible à l’intérieur du traitement d’instructions, de la procédure stockée ou du déclencheur à l’origine de l’erreur. Toutes les autres composantes de l'erreur, telles que sa gravité, son état et le texte du message contenant la chaîne de substitution (par exemple des noms d'objet) sont renvoyées seulement à l'application dans laquelle elles peuvent être traitées en utilisant les mécanismes de gestion d'erreur de l'API. Si l'erreur appelle un bloc CATCH, les fonctions système ERROR_LINE, ERROR_MESSAGE, ERROR_PROCEDURE, ERROR_NUMBER, ERROR_SEVERITY et ERROR_STATE peuvent être utilisées.