2014-12-16 5 views
0
USE [MY_DATABASE_NAME] 
GO 
/****** Object: Trigger [dbo].[trg_After_Update] Script Date: 16.12.2014 23:13:53 ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
ALTER TRIGGER [dbo].[trg_After_Update] 
ON [dbo].[MY_TABLE_NAME] 
FOR UPDATE 
AS 
    declare @FOR_DATE date; 
    declare @WRITTEN_ON smalldatetime; 
    declare @WRITTEN_BY_WHO NVARCHAR(50); 
    declare @REPORT nvarchar(max); 
    declare @HANDLED bit; 
    declare @HANDLED_BY NVARCHAR(50); 
    declare @HANDLED_WHEN datetime; 
    declare @COMMENT nvarchar(max); 
    declare @AUDIT_ACTION NVARCHAR(50); 
    declare @AUDIT_TIMESTAMP smalldatetime; 


    select @FOR_DATE  = i.FOR_DATE from inserted i; 
    select @WRITTEN_ON = i.WRITTEN_ON from inserted i; 
    select @WRITTEN_BY_WHO = i.WRITTEN_BY_WHO from inserted i; 
    select @REPORT   = i.REPORT from inserted i; 
    select @HANDLED  = i.HANDLED from inserted i; 
    select @HANDLED_BY = i.HANDLED_BY from inserted i; 
    select @HANDLED_WHEN = i.HANDLED_WHEN from inserted i; 
    select @ COMMENT  = i.COMMENT from inserted i; 

        if update(REPORT) 
     set @audit_action='Report change'; 
     if update(COMMENT) 
     set @audit_action='Comment change'; 
     if update(HANDLED) 
     set @audit_action='Handled change'; 

         insert into AUDIT_MY_TABLE_NAME 


(FOR_DATE,WRITTEN_ON,WRITTEN_BY_WHO,REPORT,HANDLED,HANDLED_BY,HANDLED_WHEN,COMMENT,USER,AUDIT_ACTION,AUDIT_TIMESTAMP) 
    values 

(@FOR_DATE,@WRITTEN_ON,@WRITTEN_BY_WHO,@REPORT,@HANDLED,@HANDLED_BY,@HANDLED_WHEN,@COMMENT,USER_NAME(USER_ID()),@audit_action,getdate()); 

이 트리거는 예상대로 작동합니다. 모니터링 된 3 개의 필드에 변경 사항을 기록합니다. 그러나이 테이블 'MY_TABLE_NAME'에 새 레코드를 삽입하면 위의 트리거가 실행됩니다. 그런 다음 감사 테이블 'AUDIT_MY_TABLE_NAME'을 (를) 볼 때이 새 레코드가 추가 된 것을 볼 수 있습니다. 유일한 차이점은 'audit_action'필드가 비어 있다는 것입니다. 감사 테이블에 삽입하는 것은 아마도 'MY_TABLE_NAME'after_insert에서 2 개의 필드를 업데이트하는 다른 트리거가 원인 일 수 있습니다.After_Update 트리거 로깅

제 질문은 이것입니다 : 나는이 방아쇠가 작동하는 방식과 비슷합니다. 내가 추가하고자하는 유일한 추가 기능은 'audit_action'이 이제는 비어있는 것을 표시하는 대신 '새 레코드'를 읽는 것입니다. 걱정하지 마세요. 새 레코드를 로깅하지는 않지만이 After_Update 트리거가 어쨌든 로그를 기록합니다. 이유는 무엇입니까? 그래서이 'after_update'트리거에서 무엇을 변경해야합니다. 그러면 새 레코드를 삽입 할 때 감사 테이블에서 '새 레코드'를 읽는 'audit_action'이 있습니까?

+1

.... –

답변

2

단일 업데이트를 위해 작성된 트리거가있을 때 매우주의해야하지만 일괄 업데이트에 대한 로깅을 방지하지는 마십시오. 일괄 처리로 20 개의 레코드를 업데이트하면 20 개의 임의의 하나가 될 감사 테이블에 1 개의 삽입이 생깁니다.

많은 것을 변경하지 않고 조건을 충족시키기 위해 다음과 같은 트리거를 수정할 수 있습니다. 그래서 (배치 업데이트를 처리합니다) :

ALTER TRIGGER [dbo].[trg_After_Update] 
ON [dbo].[MY_TABLE_NAME] 
FOR UPDATE 
AS 
    INSERT INTO AUDIT_MY_TABLE_NAME (FOR_DATE,WRITTEN_ON,WRITTEN_BY_WHO,REPORT,HANDLED,HANDLED_BY,HANDLED_WHEN,COMMENT,USER,AUDIT_ACTION,AUDIT_TIMESTAMP) 
    SELECT i.FOR_DATE, i.WRITTEN_ON, i.WRITTEN_BY_WHO, i.REPORT, i.HANDLED, i.HANDLED_BY, i.HANDLED_WHEN, i.COMMENT, USER_NAME(USER_ID()), 
     CASE -- case statement is in reverse order to match your logic (bottom wins) 
      WHEN i.HANDLED <> d.HANDLED THEN 'Handled Changed' 
      WHEN i.COMMENT <> d.COMMENT THEN 'Comment Change' 
      WHEN i.REPORT <> d.REPORT THEN 'Report Change' 
      ELSE 'New Record' 
     END, 
     GETDATE() 
    FROM inserted i 
    LEFT JOIN deleted d ON i.pk = d.pk -- join on your Primary Key that doesn't change 
END 

그러나 내가 생각하는 것이 맞는지 궁금합니다. 이 3 개의 필드 중 1 개 이상을 업데이트하면 해당 로직이 모두 실행됩니다. 3 개 중 1 개 이상의 열이 업데이트되면 마지막 열이 업데이트됩니다. 내 생각 엔 귀하의 "새 레코드"업데이트는 실제로 귀하의 3 UPDATE 열 밖에있는 필드입니다.

는 여기에 또 다른 옵션들과 난 당신이 최고라고 생각 무엇을 선택할 수 있습니다 : "20의 임의의 하나가 될 것이다"일괄 처리하지 않습니다

ALTER TRIGGER [dbo].[trg_After_Update] 
ON [dbo].[MY_TABLE_NAME] 
FOR UPDATE 
AS 
    INSERT INTO AUDIT_MY_TABLE_NAME (FOR_DATE,WRITTEN_ON,WRITTEN_BY_WHO,REPORT,HANDLED,HANDLED_BY,HANDLED_WHEN,COMMENT,USER,AUDIT_ACTION,AUDIT_TIMESTAMP) 
    SELECT i.FOR_DATE, i.WRITTEN_ON, i.WRITTEN_BY_WHO, i.REPORT, i.HANDLED, i.HANDLED_BY, i.HANDLED_WHEN, i.COMMENT, USER_NAME(USER_ID()), 
     CASE WHEN i.pk IS NOT NULL AND d.pk IS NULL THEN 'New Record' ELSE 
      CASE WHEN i.HANDLED <> d.HANDLED THEN 'Handled Changed. ' ELSE '' END + 
      CASE WHEN i.COMMENT <> d.COMMENT THEN 'Comment Change. ' ELSE '' END + 
      CASE WHEN i.REPORT <> d.REPORT THEN 'Report Change. ' ELSE '' END + 
      CASE WHEN i.HANDLED = d.HANDLED AND i.COMMENT = d.COMMENT AND i.REPORT = d.REPORT THEN 'Other Change.' ELSE '' END 
     END, 
     GETDATE() 
    FROM inserted i 
    LEFT JOIN deleted d ON i.pk = d.pk -- join on your Primary Key that doesn't change 
END 
+0

- 심지어 OP 코드가 주어지면 보장되지 않습니다. 스칼라 변수에 할당 된'inserted'에 대한 각각의 쿼리가 최종 값을 동일한 행의 해당 변수에 할당하게 될 것이라는 보장은 없습니다. 이론 상으로는 특정 행이 아닌 20 개의 행에서 나오는 매쉬 매쉬가 있습니다. –