2016-07-05 30 views
0

存儲在新表中的現有列值我有兩個表如何使用觸發

  • 客戶
  • CustomerUpdate

兩個表的結構是這樣的

客戶表的結構

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

你的觸發器有一個** **主要每行中的缺陷,你認爲它會被稱爲** **一次 - 那是**不是**的情況。它會在每個語句**中觸發一次**,所以如果你的'UPDATE'語句影響了25行,你將觸發**觸發一次**,但是'Inserted'僞表將包含25行。您的代碼在這25行中選擇哪一個? '從插入的i中選擇@NewCustomerName = i.CustomerName;' - 它是非確定性的,你將得到**一個任意的行**,並且你將**忽略所有其他行**。你需要重寫你的觸發器來考慮這個問題! –

+1

如果您想要「舊」值,您需要使用已刪除的虛擬表。當然,在審計表中,包含新值是多餘的。它將始終存在於下一個審計行或主表中。存儲兩個值需要兩倍的存儲空間。 –

回答

1

首先,從表中選擇被修改當更新觸發器正在執行時將獲得新值。這些觸發器(而不是INSTEAD觸發器)爲AFTER,因此在觸發器觸發時(儘管可以回滾),更新已經發生。如果您需要舊值,您應該從DELETED僞表中進行選擇。

其次,正如@marc_s在評論中指出的那樣,您的觸發器具有隱藏的假設,即每個更新只會影響一行。如果您的應用程序一次只更新一行,這對您的環境來說可能是一個有效的假設,但在一般情況下,每個觸發器都應該準備好處理多行受單個更新影響的情況。編寫觸發器來處理多行是很好的做法。

第三,你所有的順序執行代碼幾乎是不必要的。舊值和新值可以被檢索並插入一次全部:

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

非常感謝。 –