2015-11-06 86 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在觸發器的中間。只是不要.....