@@ERROR の使用
SQL Server 2000 以前では、@@ERROR 関数が Transact-SQL ステートメントのエラーを検出する場合の主要な手段でした。SQL Server 2005 データベース エンジン では、TRY...CATCH 構造が導入されており、エラー検出機能が強化されています。詳細については、「Transact-SQL での TRY...CATCH の使用」を参照してください。@@ERROR は、前のステートメントで発生したエラーのエラー番号も返します。SQL Server 2005 では、より多くのエラー情報を提供する他の関数が導入されています。詳細については、「Transact-SQL のエラー情報の取得」を参照してください。
@@ERROR システム関数は、最後の Transact-SQL ステートメントの実行が成功した場合は 0 を返し、エラーが発生した場合はエラー番号を返します。@@ERROR の値は、Transact-SQL ステートメントが完了するたびに変わります。
Transact-SQL ステートメントが完了するたびに @@ERROR は新しい値を取得するため、次のいずれかの方法で @@ERROR を処理します。
- Transact-SQL ステートメントの直後で @@ERROR をテストまたは使用する。
- Transact-SQL ステートメントが完了した直後に @@ERROR を整数変数に保存する。後でその変数値を使用できます。
エラーを生成するステートメントが TRY...CATCH 構造の TRY ブロックの中にない場合、エラーを生成したステートメントの直後のステートメントで、@@ERROR をテストまたは使用する必要があります。エラーを生成するステートメントが TRY ブロックの中にある場合、対応する CATCH ブロックの最初のステートメントで @@ERROR をテストまたは使用できます。CATCH ブロックのスコープの内部では、ERROR_NUMBER 関数を使用して、@@ERROR によって報告されたものと同じエラー番号を取得できます。@@ERROR は CATCH ブロック内の最初のステートメントによってリセットされますが、ERROR_NUMBER には、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 の両方を参照する場合、同じステートメント内で参照する必要があります。Transact-SQL の各ステートメントで @@ERROR および @@ROWCOUNT の両方がリセットされるため、テストされるステートメントの直後の同じステートメントでその両方を参照する必要があります。次の例では、@@ROWCOUNT は最初の PRINT ステートメントによってリセットされるまでは参照されないため、@@ROWCOUNT は常に 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 ステートメントが完了するたびに @@ERROR が 0 であるかどうかがテストされ、0 以外の場合は変数に格納されます。次に、プロシージャは RETURN ステートメントで変数を返します。プロシージャ内のどの Transact-SQL ステートメントでもエラーが発生しなかった場合は、変数は 0 のままです。1 つ以上のステートメントでエラーが発生した場合は、最後のエラー番号が変数に格納されます。このロジックを使った簡単なストアド プロシージャの例を次に示します。
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 ステートメントの間に囲んで、そのステートメントのブロックが生成したエラーを処理するために 1 つの CATCH ブロックを記述します。
CATCH ブロックの外部では、エラーを生成したバッチ、ストアド プロシージャ、またはトリガ内で使用できるデータベース エンジン のエラーとして使用できるのは @@ERROR だけです。オブジェクト名などの置換文字列を格納したメッセージ テキスト、重要度レベル、および状態など、エラーのそれ以外の部分はすべて、API のエラー処理メカニズムを使用して処理できるアプリケーションにだけ返されます。エラーが発生して CATCH ブロックが呼び出された場合、システム関数である ERROR_LINE、ERROR_MESSAGE、ERROR_PROCEDURE、ERROR_NUMBER、ERROR_SEVERITY、および ERROR_STATE を使用できます。
参照
概念
RAISERROR の使用
アプリケーションでのエラーとメッセージの処理
Transact-SQL での TRY...CATCH の使用
その他の技術情報
@@ERROR (Transact-SQL)
TRY...CATCH (Transact-SQL)
ERROR_LINE (Transact-SQL)
ERROR_MESSAGE (Transact-SQL)
ERROR_NUMBER (Transact-SQL)
ERROR_PROCEDURE (Transact-SQL)
ERROR_SEVERITY (Transact-SQL)
ERROR_STATE (Transact-SQL)