最終更新日: 7/20/2006
ホーム
> データベース>
T-SQL エラー処理 : 次のトピック
T-SQL エラー処理@@ERRORエラーがあった場合には通常、@@ERROR にエラー番号が格納されます。重要な処理を行うときには、@例 INSERT INTO table1 .... IF @@ERROR <> 0 BEGIN -- エラー処理 PRINT 'ERROR!!' ... END しかし、残念なことに続行不能なエラーが発生した場合には 直ちに処理が中断 してしまうため、@@ERROR の評価までたどりつけない!という問題があります。 この問題を回避する方法: 次のように sp_executeeql を使ってSQL の呼び出しルーチンと (失敗したときに処理が中断されてしまう) SQL の実行ルーチンを分離すればこの問題を回避できます。 sp_executesql の戻り値にはエラーコードが格納されるので、SQL の実行後、戻り値をチェックします。 例 DECLARE @res int EXEC @res = sp_executesql N'INSERT...' IF @res <> 0 BEGIN PRINT 'ERROR!!' ... END SQL Serverの実行時エラーの面倒なところは、エラーの種類によって、動作が異なるところです。 ----- コード例 (SQL 2000 以前の T-SQL) ここから
----- これでどのようなエラーが発生しても、その時点で、ロールバックして終了することになります。一方で、エラー発生時には、
即座にロールバックして終了するので、@@ERRORを判断するステートメントが実行されなくなります。そのため、上記例でも、@@ERRORを判断する
RAISERRORRAISERROR は通常はプロシージャを抜け (EXIT) ない。@@ERROR 変数が自動的にセットされる。ただし RAISERROR コマンドの重要度(sevirity)をセットすることによって処 sysmessage テーブルsysmessage テーブルに事前定義されたエラー番号/メッセージを参照することが尚、自前でエラー番号をセットするときは 50001 から使うこと。システムが使用するエラー番号上限は 50000 であるから。 @@ROWCOUNT のチェックDML ステートメント (SELECT, INSERT, UPDATE および DELETE) によってデータを変更した場合、影響を受けたレコード数は @@ROWCOUNT 変数に格納される。これはエラー番号ではないが、狙った処理が適切に行われたかチェッ 例外処理従来の @@ERROR エラー番号チェック&アクションストラテジによるコードはこのよう----- コード例 (SQL 2000 以前の T-SQL) ここから ----- BEGIN TRANSACTION DELETE [Order Details] WHERE OrderID IN (SELECT OrderID FROM Orders WHERE CustomerID = 'ALFKI') IF @@ERROR <> 0 BEGIN ROLLBACK TRANSACTION RETURN END DELETE Orders WHERE CustomerID = 'ALFKI' IF @@ERROR <> 0 BEGIN ROLLBACK TRANSACTION RETURN END DELETE Customers WHERE CustomerID = 'ALFKI' IF @@ERROR <> 0 BEGIN ROLLBACK TRANSACTION RETURN END PRINT 'I got here' -- Normally do a COMMIT TRANSACTION here. -- But I do a ROLLBACK so I don't truly delete my test data. ROLLBACK TRANSACTION ----- コード例 (SQL 2000 以前の T-SQL) ここまで ----- SQL Server 2005 では TRY/CATCH による構造化例外処理が導入されたので上記コードは次のように記述 ----- コード例 (SQL 2005 の TRY/CATCH) ここから ------ BEGIN TRY BEGIN TRANSACTION DELETE [Order Details] WHERE OrderID IN (SELECT OrderID FROM Orders WHERE CustomerID = 'ALFKI') DELETE Orders WHERE CustomerID = 'ALFKI' DELETE Customers WHERE CustomerID = 'ALFKI' PRINT 'committing deletes' COMMIT TRANSACTION END TRY BEGIN CATCH ROLLBACK TRANSACTION RETURN END CATCH ----- コード例 (SQL 2005 の TRY/CATCH) ここまで ------ CATCH ブロックでは以下のファンクションが利用可能:
ERROR_NUMBER()
ERROR_MESSAGE()
ERROR_SEVERITY()
ERROR_STATE()
ERROR_LINE()
ERROR_PROCEDURE()
CATCH ブロックでは @@error を調べるより
ERROR_NUMBER を調べたほうが良い。
SQL 2000では、TRY/CATCHが使えません。そこで、ラベルによって例外処理部を作成し、まとめてエラーを処理するようにしてみました。以下がその例 です。
----- コード例 (SQL 2000 以前の T-SQL) ここから ----- このような方法で、ソースコードの冗長性を多少でも排除することができるという点において、SQL 2000 ユーザには有用だと思います。 トランザクション処理エラー発生によって処理フローが変わり、BEGIN TRANSACTION によって開始したトランザクションを COMMIT も ROLLBACK もできない状況が起こりうる。この問題に対処するには、XACT_ABORT トグルをオンにすればよい。これをセットするとランタイムエラーが 例 SET XACT_ABORT ON とはいえ、前述の TRY/CATCH による例外処理を利用すれば、通常 COMMIT も ROLLBACK もできない状況にはならないでしょう。逆に、例外処理機構とトラン 例
CREATE
PROCEDURE Foo
AS BEGIN
RETURN ( 777 );
END RETURN 文による戻り値を ADO.NET
側で取得するには次のようにする。
例
DataTable t = new DataTable (); using ( SqlConnection conn = new SqlConnection ( "<conn string>" ) ) {
SqlCommand cmd = conn.CreateCommand (); 戻り値用のパラメータエントリを作成し (名前は任意。ここでは
@ret )、その Direction
プロパティを ParameterDirection.ReturnValue にセット。処理終了後に
Parameters["@ret"].Value として戻り値を参照する。
こ
の値は、処理が成功したときにも使用可能。
例
IF
@@ERROR <> 0 BEGIN
PRINT 'ERROR!!"; RETURN (666); ELSE BEGIN RETURN 0; END
ロックタイムアウトDB上のエラーの代表格として、ロックタイムアウトがあると思います。当然、SQL Serverも、すでにロックしているリソースに、互換性のないロックを更にかけようとした場合には、待ちが発生します。そこで、ロックタイムアウトが発生したら、しばらく待って(30秒) リトライ(100回)をするようなロジックを考えてみました。
BEGIN TRANSACTION
*WHILE 内のブロックは、SQL 2005であれば、TRY/CATCHを使ったほうが良いと思います。 |
参考資料
|