插入后使用 SQL Server 触发器更新另一个表中的列
Posted
技术标签:
【中文标题】插入后使用 SQL Server 触发器更新另一个表中的列【英文标题】:Use SQL Server trigger to update a column in another table after an insert 【发布时间】:2018-06-02 08:05:20 【问题描述】:我正在尝试使用 SQL Server 触发器完成以下操作:一旦将新行插入到表中,我想更新另一个表中的列。
例如:我有一个名为Users
的表和一个名为Activity
的表。每次客户端连接到服务器时,都会在Activity
表中插入一行;插入行后(包含user_id
),我想更新Users
表中存储上次活动的日期和时间的列。
UPDATE Users
SET Last_Activity_TimeStamp = GETDATE()
WHERE Users.User_ID = Activity.User_ID
但是 SSMS 抛出一个错误说:
无法绑定多部分标识符“dbo.Activity.User_ID”
如果我把上面的更新语句改成:
UPDATE Users
SET Last_Activity_TimeStamp = GETDATE()
WHERE Users.User_ID = User_ID
Users 表中的所有行都更新了。
我知道有一个 Inserted
表,并且这些行是在插入到主 Activity
表之前添加到那里的,但是我可能有很多用户正在连接,并且会有很多行插入到Activity
表。可能每秒 1000 次。我想知道如何将要插入的行的user_id
插入Activity
表并更新Users
表中的Last_Activity_TimeStamp
。
编辑:我想我缺乏知识的地方是我不知道任何时候Inserted
表中可以有多少行,因为在我的设计中,单个事务只插入一行。由于有多个用户连接和断开连接,是否有可能在Inserted
表中存在来自其他活动事务的不止一行?
任何帮助将不胜感激!
谢谢
【问题讨论】:
非常感谢@marc_s 的样式编辑,现在更好更清晰了。 【参考方案1】:其他响应都没有考虑到触发器中的Inserted
伪表有时会包含多个行 - 应该永远不要选择单个value - 如果一次插入多行,这将不工作。
触发器必须以基于集合的方式编写来处理这种情况 - 这真的很容易 - 尝试这样的事情:
CREATE TRIGGER trgActivityInsert
ON [dbo].[Activity]
FOR INSERT
AS
BEGIN
UPDATE u
SET Last_Activity_TimeStamp = GETDATE()
FROM dbo.Users u
INNER JOIN Inserted i ON u.User_Id = i.User_Id
END
这样,无论您一次插入一行、十行还是一百行,您的触发器都可以正常工作,并且dbo.User
表中的所有相应条目都将正确更新。
【讨论】:
太好了,我已经设法做了一些测试,你是绝对正确的。我唯一要补充的是,正如上面发布的那样,似乎 Inserted 表的范围仅限于触发器,并且由于设计上我只为每个用户的每个活动插入一行(永远不会更多),因此它将只包含一行。不过话虽如此,你的方法确实是最有效的方法,所以我将采用它。非常感谢!【参考方案2】:您不能引用 dbo.Activity.User_ID 等表字段。请像这样更改您的触发代码..
CREATE TRIGGER Trk_Test
ON [dbo].[Activity]
FOR INSERT
AS
BEGIN
DECLARE @Id INT = 0
SELECT @ID = [User_Id] FROM inserted
UPDATE Users
SET Last_Activity_TimeStamp = GETDATE()
WHERE [User_Id] = @Id
END
插入和删除的表格 Inserted / Deleted 是仅对触发器具有作用域的虚拟表。你不能在触发器之外引用。因此,无论一次连接多少用户,插入和删除的表都不会发生冲突。
【讨论】:
您的触发器有 MAJOR 缺陷,因为您似乎认为它会每行调用一次 - 那是不是 b> 情况。触发器将每条语句触发一次,因此如果您的INSERT
语句导致此触发器触发插入 25 行,您将触发触发器一次,但随后Inserted
伪表将包含 25 行。您的代码将在这 25 行中选择哪一行? SELECT @ID = [User_Id] FROM inserted
- 它是不确定的,您将获得任意行,您将忽略所有其他行。您需要重写触发器以考虑到这一点!
是的..你是对的@marc_s..但是在上面的问题中听到,如上所述,单个事务中只会插入一行......
是的 - 现在,OP 说他只插入了行 - 但将来可能会改变。不要不编写仅在某些情况下有效的代码 - 特别是如果编写正确的代码如此简单(如我自己的答案所示)
好的.. 谢谢@marc_s以上是关于插入后使用 SQL Server 触发器更新另一个表中的列的主要内容,如果未能解决你的问题,请参考以下文章