使用 @@ERROR

如果上一個 Transact-SQL 陳述式執行成功,@@ERROR 系統函數會傳回 0;如果陳述式產生錯誤,則 @@ERROR 會傳回錯誤號碼。每個 Transact-SQL 陳述式完成後,@@ERROR 的值就會改變。

因為 @@ERROR 會在每個 Transact-SQL 陳述式完成後取得新值,您可使用以下兩種方法之一來處理 @@ERROR:

  • Transact-SQL 陳述式完畢後立即測試或使用 @@ERROR。

  • 在 Transact-SQL 陳述式完成後立即以整數變數儲存 @@ERROR。這個變數值可以供之後使用。

如果陳述式產生的錯誤不是在 TRY…CATCH 建構的 TRY 區塊中,在陳述式產生錯誤後,就必須立即在陳述式中測試或使用 @@ERROR。如果陳述式產生的錯誤是在 TRY 區塊中,可以在關聯的 CATCH 區塊的第一個陳述式中測試或使用 @@ERROR。在 CATCH 區塊的範圍中,ERROR_NUMBER 函數可用以擷取 @@ERROR 所報告的相同錯誤號碼。ERROR_NUMBER 的優點在於,它可供 CATCH 區塊範圍中的所有陳述式使用,然而 @@ERROR 是由 CATCH 區塊中的第一個陳述式所重設。

條件式陳述式 (例如 IF 陳述式) 會重設 @@ERROR。如果在 IF 陳述式中參考 @@ERROR,參考 IF 或 ELSE 區塊中的 @@ERROR 將不會擷取 @@ERROR 資訊。在下列範例中,IF 重設了 @@ERROR,而且在 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

下列範例會傳回預期的結果。

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,就必須在相同的陳述式中參考它們。@@ERROR 與 @@ROWCOUNT 是以每個 Transact-SQL 陳述式來重設;因此,在測試後必須立即在相同的陳述式中同時參考它們兩個。在下列範例中,@@ROWCOUNT 永遠都是 0,因為在重設第一個 PRINT 陳述式後,才會參考它。

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 陳述式完成後,將會測試 @@ERROR 是否為 0,如果它不是 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 建構比較簡單。Transact-SQL 陳述式的區塊是由 BEGIN TRY 與 END TRY 陳述式所限定,並撰寫一個 CATCH 區塊以處理陳述式區塊可能產生的錯誤。

在 CATCH 區塊的外面,@@ERROR 是 Database Engine 錯誤中,唯一適用於產生錯誤的批次、預存程序或觸發程序的部份。此錯誤的所有其他部份,例如嚴重性、狀態和包含替代字串的訊息文字 (例如,物件名稱),僅傳至具備 API 錯誤處理機制的應用程式。如果錯誤叫用 CATCH 區塊,就會使用 ERROR_LINE、ERROR_MESSAGE、ERROR_PROCEDURE、ERROR_NUMBER、ERROR_SEVERITY 以及 ERROR_STATE。