@@ERROR 사용

@@ERROR 시스템 함수는 마지막 Transact-SQL 문이 성공적으로 실행되면 0을 반환하고 오류가 발생하면 해당 오류 번호를 반환합니다. @@ERROR의 값은 각 Transact-SQL 문이 완료될 때마다 변경됩니다.

Transact-SQL 문이 완료될 때마다 @@ERROR 값이 변경되므로 다음 두 가지 방법 중 하나로 @@ERROR를 처리합니다.

  • Transact-SQL 문이 완료된 직후에 @@ERROR를 테스트하거나 사용합니다.

  • Transact-SQL 문이 완료된 직후에 @@ERROR를 정수 변수로 저장합니다. 나중에 변수 값을 사용할 수 있습니다.

오류가 발생한 문이 TRY…CATCH 구조체의 TRY 블록에 없을 경우 오류 발생 직후에 @@ERROR를 테스트하거나 문에 사용해야 합니다. 오류가 발생한 문이 TRY…CATCH 구조체의 TRY 블록에 있을 경우 @@ERROR를 테스트하거나 관련 CATCH 블록의 첫 번째 문에 사용할 수 있습니다. CATCH 블록 내에 ERROR_NUMBER 함수를 사용하여 @@ERROR에서 보고하는 것과 동일한 오류 번호를 검색할 수 있습니다. ERROR_NUMBER는 CATCH 블록 범위의 모든 문에 사용할 수 있다는 이점이 있습니다. 이에 비해 @@ERROR는 CATCH 블록의 첫 번째 문에 의해 다시 설정됩니다.

IF 문과 같은 조건문은 @@ERROR를 다시 설정합니다. IF 문에서 @@ERROR를 참조하는 경우 IF 또는 ELSE 블록의 @@ERROR 참조는 @@ERROR 정보를 검색하지 않습니다. 다음 예에서는 @@ERROR가 IF에 의해 다시 설정되어 PRINT 문에서 @@ERROR를 참조할 때 오류 번호가 반환되지 않습니다.

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

다음 예에서는 원하는 결과를 반환합니다.

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

문이 실행된 후 @@ERROR와 @@ROWCOUNT를 모두 참조하려면 동일한 문에서 이 두 함수를 참조해야 합니다. 각 Transact-SQL 문으로 @@ERROR와 @@ROWCOUNT가 모두 다시 설정되므로 하나가 테스트된 직후에 동일한 문에서 이 두 함수를 모두 참조해야 합니다. 다음 예에서 @@ROWCOUNT는 첫 번째 PRINT 문에 의해 다시 설정될 때까지 참조되지 않으므로 항상 0입니다.

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

다음 예에서는 원하는 결과를 반환합니다.

USE AdventureWorks;
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는 오류에 대해서만 발생하며 경고에 대해서는 발생하지 않습니다. 일괄 처리, 저장 프로시저 및 트리거에서 발생한 경고를 검색하기 위해 @@ERROR를 사용할 수 없습니다.

SQL Server 2000에서 @@ERROR의 일반적인 용도는 저장 프로시저의 성공 여부를 나타내는 것입니다. 정수 변수는 0으로 초기화됩니다. 각 Transact-SQL 문이 완료되면 반환 값이 0인지 확인하기 위해 @@ERROR가 테스트되고 0이 아니면 변수로 저장됩니다. 그런 다음 RETURN 문에서 변수가 반환됩니다. 프로시저에 오류가 발생한 Transact-SQL 문이 없으면 변수는 0이지만 하나 이상의 문에서 오류가 발생하면 마지막 오류 번호가 변수에 포함됩니다. 다음 예에서는 이 논리의 간단한 저장 프로시저를 보여 줍니다.

USE AdventureWorks;
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, Title
        FROM HumanResources.Employee
        WHERE EmployeeID = @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와 TRY...CATCH 비교

오류 검색의 주요 수단으로 @@ERROR를 사용하면 TRY…CATCH 구조체에 사용되는 오류 처리 코드와는 매우 다른 스타일의 오류 처리 코드를 사용하게 됩니다.

  • 개발자는 어느 문에서 오류가 발생할지 미리 예측할 수 없기 때문에 Transact-SQL 문이 완료될 때마다 @@ERROR를 테스트하거나 저장해야 합니다. 이로 인해 지정된 논리를 구현하기 위해 코드를 작성해야 하는 Transact-SQL 문의 수가 두 배로 늘어납니다.

  • TRY…CATCH 구조체는 훨씬 더 단순합니다. BEGIN TRY 및 END TRY 문으로 Transact-SQL 문의 블록이 바인딩되고 이 블록에서 발생할 수 있는 오류를 처리하기 위한 CATCH 블록이 작성됩니다.

CATCH 블록 밖에서 @@ERROR는 오류가 발생한 일괄 처리, 저장 프로시저 또는 트리거 내에서 사용할 수 있는 데이터베이스 엔진 오류의 일부분일 뿐입니다. 개체 이름과 같은 대체 문자열을 포함하는 메시지 텍스트, 심각도 및 상태 등의 다른 오류 부분은 모두 API 오류 처리 메커니즘으로 처리될 수 있는 응용 프로그램에만 반환됩니다. 오류가 CATCH 블록을 호출할 경우 ERROR_LINE, ERROR_MESSAGE, ERROR_PROCEDURE, ERROR_NUMBER, ERROR_SEVERITY 및 ERROR_STATE 시스템 함수를 사용할 수 있습니다.