2016-07-05 13 views
0

を使用して新しいテーブル内の既存の列の値を格納します構造は、どのように私は</strong>テーブルのこの</p> <p><strong>カスタマーのようなもので二つのテーブル</p> <ul> <li>顧客の両方のテーブルの</li> <li>CUSTOMERUPDATE</li> </ul> <p>構造を持っているトリガー

CustomerName | CustomerId 

CUSTOMERUPDATEテーブルの構造

NewCustomerName | NewCustomerId | OldCustomerName 

私はCustomerテーブルに挿入されたいくつかの値を持っています。この表のデータを更新する必要があるときは、既存のデータと新しいデータを新しいテーブルCustomerUpdateにトリガーする必要があります。このため

私はトリガーを作成したが、これは変更されているテーブルから選択し、

CREATE TRIGGER trgAfterUpdate 
ON [dbo].Customer 
FOR UPDATE 
AS 
    SET NOCOUNT ON 

    declare @NewCustomerName nchar(20); 
    declare @NewCustomerId nchar(20); 
    declare @OldCustomerName nchar(20); 
    declare @audit_action varchar(100); 

    select @NewCustomerName = i.CustomerName from inserted i; 
    select @NewCustomerId = i.CustomerId from inserted i; 

    select @OldCustomerName = c.CustomerName 
    from Customer c 
    where CustomerId = @NewCustomerId; 

    if update(CustomerName) 
     set @audit_action='Updated Record -- After Update Trigger.'; 

    if update(CustomerId) 
     set @audit_action='Updated Record -- After Update Trigger.'; 

    insert into CustomerUpdate(NewCustomerName, NewCustomerId, OldCustomername) 
    values(@NewCustomerName, @NewCustomerId, @OldCustomerName); 

    PRINT 'AFTER UPDATE Trigger fired.' 
GO 

+3

あなたのトリガがあり** MAJOR **という点で欠陥あなたはそれが呼び出されることになりますと仮定**一度行あたり** - その** **の場合はありません。文**で1回**を起動するので、 'UPDATE'文が25行に影響を与えると、トリガは一度**発生しますが、' Inserted'擬似表には25行が含まれます。あなたのコードがここで選択する25行のうちどれですか? 'select @NewCustomerName = i.CustomerName from i;挿入されていません - これは非決定的なものです**あなたは任意の行**を取得し、**あなたは**他のすべての行を無視します**。これを考慮に入れてトリガーを書き直す必要があります。 –

+1

"古い"値が必要な場合は、削除された仮想テーブルを使用する必要があります。もちろん、監査テーブルでは、新しい値を含めるのは冗長です。それは常に次の監査行またはメイン表のいずれかに存在します。両方の値を格納するのに2倍の記憶域が必要です。 –

答えて

1

最初に私を助けてください...それは、既存のデータを引っ張っていない、更新されたデータを引っ張っています更新トリガが実行されているときに新しい値が取得されます。これらはAFTERトリガー(INSTEADトリガーではなく)です。したがって、トリガーが起動するまでに(ロールバックすることはできますが)更新が既に発生しています。古い値が必要な場合は、疑似テーブルDELETEDから選択する必要があります。

第2に、コメントで@marc_sが指摘しているように、トリガには、各更新によって影響を受ける行は1つだけであるという隠れた仮定があります。アプリケーションが一度に1つの行しか更新しない場合は、環境に対して有効な仮定である可能性がありますが、一般的なケースでは、多くの行が単一の更新の影響を受けるケースを処理する準備ができているはずです。複数の行を処理するためのトリガーを書くことは良い方法です。

第3に、順番に実行されているコードはすべてほとんど不要です。古い値と新しい値が取得され、すべてを一度に挿入することができます。

CREATE TRIGGER trgAfterUpdate 
ON [dbo].Customer 
FOR UPDATE 
AS 
BEGIN 
    SET NOCOUNT ON 
    insert into CustomerUpdate(NewCustomerName, NewCustomerId, OldCustomername) 
    -- case 1: ID unchanged 
    SELECT I.CustomerName, I.CustomerID, D.CustomerName 
    FROM Inserted I 
    JOIN Deleted D on I.CustomerID=D.CustomerID 
    UNION ALL 
    -- case 2: ID changed, Name unchanged 
    SELECT I.CustomerName, I.CustomerID, D.CustomerName 
    FROM Inserted I 
    JOIN Deleted D on I.CustomerName=D.CustomerName 
    WHERE I.CustomerID<>D.CustomerID 
    UNION ALL 
    --case 3: ID changed, Name changed 
    SELECT I.CustomerName, I.CustomerID, D.CustomerName 
    FROM Inserted I 
    LEFT JOIN Deleted D on I.CustomerID=D.CustomerID OR I.CustomerName=D.CustomerName 
    WHERE D.CustomerID IS NULL; 
END 
+0

ありがとうございます。 –

関連する問題

 関連する問題