我有一个表格customers_accounts
,该表格跟踪有关帐户中客户的一些基本信息。打开客户的文件后,我将同步来自外部系统的信息,以便我们的用户获得最新的信息。
UPDATE
customers_accounts
SET
first_name = 'bob',
last_name = 'burger'
WHERE
account_number = '12345'
当用户更新帐户时,我会执行相同的查询,但是会更新一列,指示最后一位进行更改的用户
UPDATE
customers_accounts
SET
first_name = 'bob',
last_name = 'burger',
updated_by = 'H Jon Benjamin',
updated_on = GETDATE()
WHERE
account_number = '12345'
这是我要解决的问题。我想跟踪历史记录表中的更改,但是仅在用户进行更改时才记录更改,而不是在外部系统中记录更改。所以我的计划是创建一个触发器,如果插入的用户列不为空,则会插入一行(因为在第一次更新中,updated_by
隐式为null)
我尝试过的是:
ALTER trigger [dbo].[Accounts_Customers_LogUpdate]
ON [dbo].[Accounts_Customers]
AFTER UPDATE
AS
DECLARE @Now AS DATETIME = GETDATE()
DECLARE @User AS NVARCHAR(150)
SELECT @User = (SELECT [updated_by] FROM INSERTED)
IF (@User IS NOT NULL)
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[Accounts_Customers-History]
SELECT *, @User, @Now
FROM inserted
END
Accounts_Customers-History
是表的精确副本,另外还有两列change_made_by
和change_made_on
它不符合我的期望。它将updated_by
中的任何值插入change_made_by
中,而不管查询中updated_by
的值如何。因此,我得到了由用户和导入触发的记录活动。
答案 0 :(得分:2)
为此使用UPDATE()
:
返回一个布尔值,该布尔值指示是否对表或视图的指定列进行了INSERT或UPDATE尝试。 UPDATE()用于Transact-SQL INSERT或UPDATE触发器体内的任何位置,以测试该触发器是否应执行某些操作。
这意味着update
函数将为问题中的第一条更新语句返回false
,并为第二条更新语句返回true
-这正是您所需要的。>
此外,请注意,您应始终在插入语句中指定列列表, 并且还要始终在select语句中指定列列表。 (Why?)
触发器的修订版可能看起来像这样:
ALTER TRIGGER [dbo].[Accounts_Customers_LogUpdate]
ON [dbo].[Accounts_Customers]
AFTER UPDATE
AS
DECLARE @Now as DateTime = GetDate()
IF UPDATE(updated_by)
BEGIN
-- Always specify the columns list in an insert statement!
insert into [dbo].[Accounts_Customers-History] (<Columns list>)
-- Always specify the columns list in a select statement!
select <columns list>, @Now
from inserted
END
请注意,UPDATE()
函数不会向您发出任何触发触发器的插入或更新语句是否成功的指示,也不会给您指示该列的值是否实际上已更改-仅指示该列是否是触发触发器的insert或update语句的一部分-如您在备注部分的最后一段中所读:
如果触发器应用于列,则即使列值保持不变,UPDATED值也将返回true或1。这是设计使然,触发器应实现确定插入/更新/删除操作是否允许的业务逻辑。