2009-05-19 15 views
11

でのtry-catchを取引私は、Microsoftのサーバーに2005TSQL:トリガー

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文を入れしようとしていますが、問題は、私は場合は、トリガーが失敗したくないということです何かがtry-catchブロックによって捕らえられます。現時点では、「トランザクションがトリガで終了しました。バッチが中止されました」というエラーが表示されます。トランザクションが失敗した場合。どのようにトリガを正常に失敗させることができますか?


さらに、トランザクションを削除すると、「トランザクションが破棄されました。バッチが中止されました」というエラーが表示されます。

BEGIN TRY 
    --Some More SQL 
END TRY 
BEGIN CATCH 
    return 
END CATCH 

これには何らかの方法がありますか?

+0

: 次のコードは、トリガーを作成することです。問題は、トリガーが失敗した場合に挿入を失敗させたくないということです。レガシーデータベースは最も信頼性の高いシステムではありません。 – Eldila

+13

私は、より多くのエラーメッセージで "運命"という言葉を使い始めるつもりです。 – AaronLS

答えて

7

トリガーでロールバックしないでください。トランザクションを開始する必要もありません。

ROLLBACK TRANSACTIONは、オリジナルのDMLトリガーを余分なトリガー・トランザクションにもロールバックします。だから、バッチが中止されます

編集:

私はあなたのcatchブロックで「RETURN」を有すると単にコードは、私がトリガーにトラップされたエラーを無視したことがありません を完了することはできませ示唆している(ただし、Iこれは推測ですが、戻り値はおそらくトリガーの異常終了条件である可能性があります。

また、最初の場所でエラー状態を回避しようとしています。エラーが発生しないように--some more sqlを変更してください。例:if exists(...を追加して、最初の重複をテストします。

+0

これは本当に役に立ちます。しかし、私はちょうど別の問題に遭遇しました。詳細については、更新された質問をご覧ください。残念ながら – Eldila

+1

、トリガーで 'ROLLBACK'なし - 非常に厄介で、完全に.NETトランザクションのサポートをマックすることができます! - 私はトリガーで*の制約を絶対に強制する方法を知らない。 'RAISERROR(...、16,1)は' NETの通知を行い、多くの場合に例外をスローするのに十分ですが、「自動コミット」取引(IMPLICIT_TRANSACTIONS = OFF)は* 'RAISERROR'となりますので、バイパスで*の影響を受けませんこのトリガーが追加しようとしていた制約。私が見つけた唯一の "解決策"は、 "自動コミット"トランザクションを使用せず、明示的にROLLBACK/COMMITをTRY/CATCHと使用することです。最悪。設計。これまで –

+0

(もちろん、Sybaseが完全に実行可能な 'ROLLBACK TRIGGER'があります: - /) –

8

私の経験では、トリガーでtry catchで捕捉されたエラーがトランザクション全体をロールバックします。セーブトランザクションを使用することができます。私はあなたが "いくつかのより多くのSQL"で起こっていることを見て、それを回避するためにcase/if文を書くことができるかどうかを判断する必要があると思います。

あなたはあなたが何をしているかに応じて、可能なTODOかもしれするsave transactionを使用して、あなたのコードでその漁獲量

にこの

SAVE TRANSACTION BeforeUpdate; 
BEGIN TRY 
     --Some More SQL 
END TRY 
BEGIN CATCH 
ROLLBACK TRANSACTION BeforeUpdate; 
     return 
END CATCH 
+0

Iは、SAVE TRANSACTION +1知りませんでした – ichiban

+0

その存在しばらくして:)ので、控えめに使用しても、それは衝撃性能を行います。 – u07ch

+1

オープンな取引が必要であるということですか?引き金の始まりにそれを開くことができますか? – meir

1

u07ch、残念ながら

のようなものをキャプチャしていますトランザクションを保存して一緒にキャッチしようとすることはできません。一緒に作業することはできません。

http://sqlblog.com/blogs/alexander_kuznetsov/archive/2008/11/15/avoid-mixing-old-and-new-styles-of-error-handling.aspx

+1

これは可能です。 [ここにMicrosoftの例があります](http://msdn.microsoft.com/en-us/library/ms188378.aspx)それはちょうどピタです。あなたはトランザクションを作成したかどうかを知る必要があります。次に、クリーンアップ時にXACT_STATEを調べる必要があります。これはトリガーの文脈でさえも*完全に醜いものです。私はSQL Serverのトランザクションと "例外処理"が嫌いです。 –

+0

@pstすることはできません。トランザクションが破綻した場合、セーブポイントにロールバックする方法はありません。あなたができるのは、全体のトランザクションをロールバックすることだけです。 –

+0

自然に...この例もこのケースをカバーしています。 –

0

トリガであなたが何をしようとしているかを知ることは役に立ちます。

トリガーは、挿入または削除されたテーブルにデータを送信したトランザクションの一部です。失敗した場合は、トランザクション全体をロールバックします。トリガが失敗することがあると思いますが、トリガを起動した文をロールバックしない場合は、トリガが正しいかどうか再考する必要があります。

+0

その代わりに何を使用しますか? – Joel

2

前トリガーアクションにトランザクションデータを失うことを避けるために、あなたはTRANをCOMMIT呼び出したいでしょう。 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. 

しかし、元のトランザクションとトリガートランザクションの両方が正常にコミットする必要があります。

UPDATE: TRY文の中でBEGIN TRANを呼び出して、例外最後のエラーを回避するには。注:トリガ内でCOMMIT TRANを呼び出さないことをお勧めしますが、やむを得ない場合は、これが有効です。

例:

COMMIT TRAN 
BEGIN TRY 
    BEGIN TRAN 
1

は最善の方法はありませんが、それは動作します。新しいトランザクションを開始し、通常のコミット、ロールバックを行うと、暗黙的なトランザクションのために最後に別のトランザクションを開始しますが、トリガーの初めにOFFにXACT_ABORTを設定することができます

http://msdn.microsoft.com/en-us/library/ms187844(v=SQL.90).aspx

0

をコミットします。

1

このデモでは、上記尋ねた事柄の多くを実現しています。エラーメッセージはオプションになります。それを動作させるトリックは、ネストされた動的実行です。

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 
1

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