2012-02-02 15 views
1

SQL Server 2005には、特定のフィールドの監査の変更を追跡するためのトリガーがあります。私たちは別のテーブルの変更を追跡します。このトリガーは、意図したとおりの単一のレコード項目に対して期待どおりに機能しますが、バルク更新を介して列に加えられた変更を追跡する必要があります。カーソルのないトリガー一括更新

現在のトリガ:

Subquery returned more than 1 value. This is not permitted when the subquery 
follows =, !=, <, <= , >, >= or when the subquery is used as an expression. 

どのように私は、一括更新のために働くために私の現在のトリガーを変更することができます。

CREATE TRIGGER [dbo].[trg_LogChanges] 
    ON [dbo].[Test] 
    FOR UPDATE 
AS 

DECLARE @TableName VARCHAR(100) , 
    @UpdatedDate smalldatetime , 
    @UpdatedBy uniqueidentifier 

SELECT @TableName = 'dbo.Test' 

IF(SELECT COUNT(*) FROM INSERTED) = 1 
    BEGIN 
     IF(SELECT LastModifiedDate FROM INSERTED) Is Null 
     SET @UpdatedDate = getdate() 
     ELSE 
     SET @UpdatedDate = (SELECT LastModifiedDate FROM INSERTED) 

     IF(SELECT LastModifiedBy FROM INSERTED) Is Null 
     SET @UpdatedBy = '11111111-1111-1111-1111-111111111111' 
     ELSE 
     SET @UpdatedBy = (SELECT LastModifiedBy FROM INSERTED) 

      IF UPDATE (ActDate) 
     BEGIN 
     INSERT INTO dbo.LogChanges 
     (
      ChangeType 
      , TableName 
      , RecordGuid 
      , FieldName 
      , OldValue 
      , NewValue 
      , UpdatedBy 
      , UpdatedDate 
     ) 
     SELECT 
      'U' 
      , @TableName 
      , d.Guid 
      , 'ActDate' 
      , d.ActDate 
      , i.ActDate 
      , @UpdatedBy 
      , @UpdatedDate 
     FROM INSERTED i 
     INNER JOIN DELETED d 
      on i.Guid = d.Guid 
     WHERE 
      (d.ActDate IS NULL AND i.ActDate IS NOT NULL) 
      OR (d.ActDate IS NOT NULL AND i.ActDate IS NULL) 
      OR (d.ActDate <> i.ActDate) 
     END 
     -- this keeps going for each field that we need to get the Audit Trail on 
    END 
ELSE 
    BEGIN 
     -- now I need to track for multiple records 
     -- I tried changing the WHERE clause above to see if it would work for bulk updates 
     INSERT INTO... 
     SELECT... 
     WHERE 
    (
     (d.ActDate IS NULL AND i.ActDate IS NOT NULL) 
     OR (d.ActDate IS NOT NULL AND i.ActDate IS NULL) 
     OR (d.ActDate <> i.ActDate) 
    ) 
    AND d.ActDate IN (SELECT d.ActDate FROM DELETED d) 
    END 

このコードは、エラーがスローされます複数のレコードでは動作しません。それを行うにはカーソルを使用する必要がありますか?もしそうなら、誰かがサンプルコードを提供できますか?

+0

よく、あなたの最後のINSERTの 'SELECT'が重要です。すべてのコード – Lamak

+0

を表示してください。選択は単一項目のものと同じです。 – Taryn

答えて

2

複数のレコードがある場合、どのように@UpdatedDateと@UpdatedByを設定していますか?私はあなたがこのようなことをしていると思っています。これはあなたが1つのレコードに対してやっていることです。

IF(SELECT LastModifiedBy FROM INSERTED) Is Null 
    SET @UpdatedBy = '11111111-1111-1111-1111-111111111111' 
ELSE 
SET @UpdatedBy = (SELECT LastModifiedBy FROM INSERTED) 

ELSEの下にあるSETは、INSERTEDに複数の行があるとエラーを引き起こします。

はこの1つだけ含む任意の数のレコード、のために働く必要があります

INSERT INTO dbo.LogChanges 
(
ChangeType 
, TableName 
, RecordGuid 
, FieldName 
, OldValue 
, NewValue 
, UpdatedBy 
, UpdatedDate 
) 
SELECT 
'U' 
, @TableName 
, d.Guid 
, 'ActDate' 
, d.ActDate 
, i.ActDate 
, ISNULL(LastModifiedBy, '11111111-1111-1111-1111-111111111111') 
, ISNULL(LastModifiedDate, getdate()) 
FROM INSERTED i 
INNER JOIN DELETED d 
    on i.Guid = d.Guid 
WHERE (d.ActDate IS NULL AND i.ActDate IS NOT NULL) 
    OR (d.ActDate IS NOT NULL AND i.ActDate IS NULL) 
    OR (d.ActDate <> i.ActDate) 

代わりにこれを試してみてください。私はUPDATE(ActDate)をチェックしていないことに注意してください。 ActDateが変更されなかった場合、レコードは返されません。

+0

ありがとうございます。私はそれがエラーを投げていたlastmodifiedby/lastmodifieddateのための私の最初の選択された声明だったことに気付かなかった – Taryn

関連する問題