如何使用触发器在新表中存储现有列值

时间:2016-07-05 16:32:12

标签: sql-server triggers

我有两张桌子

  • 客户
  • 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

请帮帮我

1 个答案:

答案 0 :(得分:1)

首先,在执行更新触发器时从正在修改的表中进行选择将获得新值。这些是AFTER触发器(而不是INSTEAD触发器),因此在触发器触发时已经发生了更新(尽管可以回滚)。如果您需要旧值,则应从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