我有以下查询,它更新 10 条记录的时间戳。
UPDATE [dbo].[file] SET timestamp = GETDATE() WHERE id <= 10
我在该表插入/更新上创建了一个触发器。
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[trg_file]
ON [dbo].[file]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ID BIGINT;
DECLARE @RES VARCHAR(100);
SET @ID = (select id from INSERTED);
SET @RES = (select timestamp from INSERTED);
IF @RES IS NOT NULL
DELETE FROM [dbo].[file] WHERE id IN (@ID)
END
它给出了错误
Msg 512, Level 16, State 1, Procedure trg_file
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
The statement has been terminated.
似乎问题就在这里,因为它同时获得了多个记录。
SET @ID = (select id from INSERTED);
如何解决呢?通过光标我看到了一些帖子。
我想将触发器应用于多个值更新。
哪个是最好的解决方案?
您需要确保在触发器中执行的任何操作都可以处理多行。正如 Akina 建议的那样,您可以将 @ID 值限制为单个修改值,但这可能不是您想要的。
您发送的示例触发器中没有任何实际逻辑,因此我在此处提供了一个示例,说明使用允许多行修改的 INSERTED 表可以完成哪些操作。
为了复制上面建立的逻辑,此示例展示了一种实现方法。
当您位于触发器内时,您可以访问两个虚拟表。插入和删除。它们具有与基表相同的列。INSERTED 表具有 NEW 值(如果在 AFTER 触发器中,则相当于 CURRENT 值)。DELETED 表包含 PRIOR 和 DELETED 行。
如果 DELETED 表中存在某行但 INSERTED 表中不存在该行,则该行已被删除。您可以比较 DELETED 和 INSERTED 表的值以查看更改的值(确保考虑 NULL)。
但是,这里您需要小心,INSERTED 表包含所有值,即使时间戳没有更改,因此您需要执行更多逻辑以确保仅在时间戳值实际更改时才删除。
这是实现这一目标的更好方法之一(根据我的经验)。
这将检测时间戳值的任何更改。它将允许在首次创建行时设置时间戳值,但是,此后将不允许更改该值(即使它是使用 NULL 值创建的)。