我有两张桌子
两个表的结构都是这样的
客户表的结构
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
请帮帮我
答案 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