2015-11-06 88 views
0

我是新来的SQL Server错误处理,我的英文不太清楚,所以我提前道歉,任何误解。SQL SERVER错误处理光标里面的触发器

问题是:我插入多​​个记录到表中。该表具有一个AFTER INSERT触发器,该触发器正在使用游标在FETCH WHILE循环中逐个处理记录。如果发生错误,所有事情都会回滚。所以如果在插入的记录中只有一个错误的字段,我就会全部丢失。插入也回滚,所以我找不到错误的记录。所以我需要处理游标内部的错误,只回滚错误的记录。

我与3个表测试数据库:

TA

VarSmallint smallint 
VarTinyint tinyint 
String varchar(20) 

TB

ID int (PK, identity) 
Timestamp datetime (default: getdate()) 
VarSmallint smallint 
VarTinyint tinyint 
String varchar(20) 

的tC

ID int PK 
Timestamp datetime 
VarTinyint1 tinyint 
VarTinyint2 tinyint 
String varchar(10) 

tA包含3条记录,1条错误。我将这个内容插入tBtB具有触发器,并将记录插入到tC中。

tC只有tinyint变量,所以插入大于255的值可能会有问题。这是测试错误发生的地方!

我的触发是:

ALTER TRIGGER [dbo].[trg_tB] 
ON [dbo].[tB] 
AFTER INSERT 
AS 
BEGIN 
    IF @@rowcount = 0 
     RETURN; 

    SET NOCOUNT ON; 

    DECLARE 
     @ID    AS int, 
     @Timestamp  AS datetime, 
     @VarSmallint AS smallint, 
     @VarTinyint  AS tinyint, 
     @String   AS varchar(20), 

    DECLARE curNyers CURSOR DYNAMIC 
    FOR 
     SELECT 
      [ID], [Timestamp], [VarSmallint], [VarTinyint], [String] 
     FROM INSERTED 
     ORDER BY [ID] 

    OPEN curNyers 

    FETCH NEXT FROM curNyers INTO @ID, @Timestamp, @VarSmallint, @VarTinyint, @String 

    WHILE @@FETCH_STATUS = 0 
    BEGIN 
    BEGIN TRY 
     BEGIN TRAN 

     INSERT INTO [dbo].[tC]([ID], [Timestamp], [VarTinyint1], [VarTinyint2], [String]) 
     VALUES (@ID, @Timestamp, @VarSmallint, @VarTinyint, @String) 

     COMMIT TRAN 
    END TRY 
    BEGIN CATCH 
     ROLLBACK TRAN 

     INSERT INTO [dbo].[tErrorLog]([ErrorTime], [UserName], [ErrorNumber], 
             [ErrorSeverity], [ErrorState], 
             [ErrorProcedure], [ErrorLine], 
             [ErrorMessage], [RecordID]) 
     VALUES (SYSDATETIME(), SUSER_NAME(), ERROR_NUMBER(), 
       ERROR_SEVERITY(), ERROR_STATE(), 
       ERROR_PROCEDURE(), ERROR_LINE(), 
       ERROR_MESSAGE(), @ID) 

     END CATCH 

     FETCH NEXT FROM curNyers INTO @ID, @Timestamp, @VarSmallint, @VarTinyint, @String 
    END 

    CLOSE curNyers 
    DEALLOCATE curNyers 
END 

如果我插入2条1点错了,一切都回滚良好的记录,我得到了一个错误:

Msg 3609, Level 16, State 1, Line 1
The transaction ended in the trigger. The batch has been aborted.

请帮帮我!如何修改此触发器以正常工作?

如果我插入错误的记录,我需要:

  1. 所有结核病
  2. 一切美好的记录插入记录的tC
  3. 错误tErrorLog

感谢登录!

回答

0

我删除了TRIGGER,复制粘贴,从它的代码为STORED PROCEDURE

然后,我添加一行Status到TB,并设置缺省值为0

1“记录处理OK”,2为“记录处理故障”。

我填的是光标WHERE Status = 0

TRY部分,我将状态更新为1,在CATCH部分我把它UPDATE为2

我没有工作,所以我从Windows运行调度的SP用的SQLCMD命令的批处理文件。

现在的处理效果很好,而且效果不错,第一次。谢谢您的帮助!

1

您的触发两大灾害

  1. 不使用光标触发器内 - 这只是太可怕了!触发器在给定操作发生时触发 - 您无法控制何时触发多少次。因此,为了不太多危害您的系统性能,触发器应该是非常小,速度快,灵活 - 做做一个触发任何繁重和广泛的处理。游标是什么,但灵活和快速的 - 这是一个资源猪,处理器生猪,内存泄漏的怪物 - AVOID这些时,你就可以了,最绝的触发器内! (你不需要他们,99%的情况下,无论如何)

    你可以重写你的整个逻辑到这一个单一的,快速的,基于集的声明:

    ALTER TRIGGER [dbo].[trg_tB] 
    ON [dbo].[tB] 
    AFTER INSERT 
    AS 
    BEGIN 
        INSERT INTO [dbo].[tC]([ID], [Timestamp], [VarTinyint1], [VarTinyint2], [String]) 
         SELECT 
          [ID], [Timestamp], [VarSmallint], [VarTinyint], [String] 
         FROM 
          INSERTED 
    END 
    
  2. ,一定不要调用COMMIT TRAN在触发器内。触发器在引起它触发的语句的上下文和事务内部执行 - 如果一切正常,只需让触发器完成,然后事务就会被提交。如果您需要中止,请致电ROLLBACK。但是永远电话COMMIT TRAN在触发器的中间。只是不要.....