如何忽略触发器中的错误并在MS SQL Server中执行相应的操作

时间:2013-07-18 12:05:38

标签: sql sql-server sql-server-2008 triggers

我创建了AFTER INSERT TRIGGER

现在,如果在执行Trigger时发生错误,则为任何情况。它不应该在触发表上影响插入操作。

如果在触发器中发生任何ERROR,则应该忽略它。

我用过

BEGIN TRY

END TRY
BEGIN CATCH

END CATCH

但它会在触发表

上提供以下错误消息并回滚插入操作
  

触发器执行期间出错。批次已经   已中止,用户事务(如果有)已回滚。

3 个答案:

答案 0 :(得分:4)

有趣的问题。默认情况下,设计触发器,如果​​它们失败,则会回滚触发它的命令。因此,无论何时执行触发器,都存在活动事务,无论外部是否存在明确的BEGIN TRANSACTION。并且BEGIN / TRY内部触发器也不起作用。你的最佳做法是不要在可能失败的触发器中编写任何代码 - 除非希望也使得触发语句失败。

在这种情况下,为了抑制这种行为,有一些解决方法。

选项A(丑陋的方式):

由于事务在触发开始时处于活动状态,您只需COMMIT它并继续执行触发命令:

CREATE TRIGGER tgTest1 ON Test1 AFTER INSERT
AS
BEGIN
COMMIT;
... do whatever trigger does
END;

请注意,如果触发代码中存在错误,则仍会产生错误消息,但Test1表中的数据会安全插入。

选项B(也很难看):

您可以将代码从触发器移动到存储过程。然后从实现BEGIN/TRY的Wrapper SP调用该存储过程,最后从触发器调用Wrapper SP。如果在逻辑中需要在INSERTED表中移动数据可能有点棘手(现在在SP中) - 可能使用一些临时表。

<强> SQLFiddle DEMO

答案 1 :(得分:2)

你不能,任何解决它的尝试都是蛇油。没有任何数量的TRY / CATCH或@@ ERROR检查可以解决这个基本问题。

如果你想使用紧密耦合的触发器,那么你必须购买由耦合引起的较低的可用性。

如果要保留可用性(即INSERT成功),则必须放弃耦合(删除触发器)。您必须在提交 INSERT后启动的单独事务中执行您计划在触发器中执行的所有处理。一个SQL代理作业轮询表中新插入的行,Service Broker启动的过程甚至应用程序层步骤都符合要求。

答案 2 :(得分:0)

接受的答案的选项A给了我以下错误:“事务在触发器中结束。批处理已中止。”。我通过使用下面的SQL规避了这个问题。

CREATE TRIGGER tgTest1 ON Test1 AFTER INSERT
AS
BEGIN
    SET XACT_ABORT OFF
    BEGIN TRY  
        SELECT [Column1] INTO #TableInserted FROM [inserted]
        EXECUTE sp_executesql N'INSERT INTO [Table]([Column1]) SELECT [Column1] FROM #TableInserted'
    END TRY  
    BEGIN CATCH
    END CATCH
    SET XACT_ABORT ON
END