Microsoft Server 2005を使用して、トリガー内にtry-catchステートメントを配置しようとしています。
BEGIN TRANSACTION
BEGIN TRY
--Some More SQL
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF (XACT_STATE()) = -1
BEGIN
ROLLBACK TRANSACTION;
END;
END CATCH
問題は、try-catchブロックによって何かがキャッチされた場合にトリガーが失敗することを望まないことです。現時点では、「トランザクションはトリガーで終了しました。バッチは中止されました。」というエラーが表示されます。トランザクションが失敗した場合。トリガーを正常に失敗させるにはどうすればよいですか?
さらに、トランザクションを削除すると、「トランザクションはトリガーで運命づけられました。バッチは中止されました。」というエラーが表示されます。
BEGIN TRY
--Some More SQL
END TRY
BEGIN CATCH
return
END CATCH
これを回避する方法はありますか?
私の経験では、トリガーのtry catchでキャッチされたエラーは、トランザクション全体をロールバックします。保存トランザクションを使用できる場合があります。 「Somemoresql」で何が起こっているのかを見て、エラーを止めるためにcase/ifステートメントを記述できるかどうかを判断する必要があると思います。
何をしているかによっては、 トランザクションの保存 を使用して、それをキャッチに取り込むことができる場合があります。
あなたのコードではこのようなもの
SAVE TRANSACTION BeforeUpdate;
BEGIN TRY
--Some More SQL
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION BeforeUpdate;
return
END CATCH
トリガーでロールバックしないでください。トランザクションを開始する必要もありません。
ROLLBACK TRANSACTION
は、元のDMLトリガーをロールバックしますおよび追加のトリガートランザクションも。したがって、バッチは中止されます
編集:
キャッチブロックに「RETURN」を含めず、コードを完了させることをお勧めします。トリガーでトラップされたエラーを無視したことはありません(ただし、ロールバックとレイザーを使用してトリガーでTRY/CATCHを使用して再スローします)。これは推測ですが、リターンはおそらくトリガーの異常な終了条件です
また、そもそもエラー状態を回避するようにしてください。エラーを回避するには、--some more sql
を変更してください。例、if exists(...
を追加して、最初に重複などをテストします
SET XACT_ABORT OFFを使用します。Transact-SQLステートメントでエラーが発生すると、エラーメッセージが表示され、トランザクションは処理を続行します。次のコードは、トリガーを作成するためのものです。
Create TRIGGER [dbo].tr_Ins_Table_Master ON [dbo].Table_Master
AFTER INSERT
AS
BEGIN
set xact_abort off
BEGIN TRY
--your SQL
INSERT INTO Table_Detail
SELECT MasterID,Name FROM INSERTED
END TRY
BEGIN CATCH
select ERROR_MESSAGE()
END CATCH
END
トリガーアクションの前にトランザクションデータが失われないようにするには、COMMITTRANを呼び出す必要があります。 TRY/CATCHブロックの前にこれを行うと、希望する結果が得られます。
例:
COMMIT TRAN
BEGIN TRY
-- possible error occurs here...
END TRY
BEGIN CATCH
PRINT 'Error on line ' + CAST(ERROR_LINE() AS VARCHAR(10))
PRINT ERROR_MESSAGE()
END CATCH
それでも次のエラーがスローされます-回避方法がわかりません:
The transaction ended in the trigger. The batch has been aborted.
ただし、元のトランザクションとトリガートランザクションの両方が正常にコミットされるはずです。
更新:例外の最後のエラーを回避するには、TRYステートメント内でBEGINTRANを呼び出します。 Microsoftは、トリガー内でCOMMIT TRANを呼び出さないことをお勧めしますが、やむを得ない場合は、これでうまくいくはずです。
例:
COMMIT TRAN
BEGIN TRY
BEGIN TRAN
このデモは、上記で求められた多くのことを実現します。エラーメッセージはオプションになります。それを機能させる秘訣は、ネストされた動的実行にあります。
if object_id('toto') is not null drop table toto
go
create table toto (i int);
go
if object_id('toto2') is not null drop table toto2
go
create table toto2 (i int);
go
create Trigger trtoto
ON toto
Instead Of Insert
as
Begin
BEGIN TRY
set nocount on
insert into toto values(2)
declare @sql nvarchar(max) = 'insert into toto2 values(3); select * from ThisTableDoesntexist'
Exec sp_executeSql N'set xact_abort off; exec (@sql) ', N'@sql nvarchar(max)', @sql
END TRY
BEGIN CATCH
PRINT 'Error on line ' + CAST(ERROR_LINE() AS VARCHAR(10))
PRINT ERROR_MESSAGE()
END CATCH
End
GO
-- tests
set nocount on
insert into toto values (1) -- is not inserted on purpose by the trigger
select * from toto -- other value inserted despite the error
select * from toto2 -- other value inserted in other table despite the error
最善の方法ではありませんが、機能します。新しいトランザクションを開始し、通常のコミットロールバックを実行して、暗黙的なトランザクションコミットのために最後に別のトランザクションを開始します
http://msdn.Microsoft.com/en-us/library/ms187844(v = SQL.90).aspx
トリガーで何をしようとしているのかを知ることが役立つ場合があります。
トリガーは、挿入または削除されたテーブルにデータを送信したトランザクションの一部です。失敗した場合は、トランザクション全体をロールバックします。トリガーがときどき失敗することを期待しているが、トリガーを起動させたステートメントをロールバックしない場合は、トリガーを使用するのが正しいかどうかを再考する必要があります。
u07ch、
残念ながら、保存トランザクションを使用して試行することはできません。一緒にキャッチします。単に一緒に機能することはできません。
トリガーの開始時にXACT_AbortをOFFに設定できます。