【发布时间】:2020-01-03 09:56:25
【问题描述】:
我有一个表,我想在其中触发更新操作:
ALTER TRIGGER [dbo].[cmt_update]
ON [dbo].[comments]
FOR UPDATE
AS
DECLARE @Cinfo VARBINARY(128)
SELECT @Cinfo = Context_Info()
IF @Cinfo = 0x55555
RETURN
-- insert into syncro requests
INSERT INTO syncros_requests (db_table_name, db_table_id, action_type, request_date, syncro_status, syncro_msg, creation_date, usr, edition_date, usr_edition)
SELECT
'comments', id, 'U', GETDATE(), 'NS', '', GETDATE(), usr, GETDATE(), usr
FROM
inserted
IF (select pendent from deleted) = 0 AND (select pendent from inserted) = 1
-- insert into syncro requests
insert into syncros_requests(db_table_name, db_table_id, action_type, request_date, syncro_status, syncro_msg, creation_date, usr, edition_date, usr_edition)
select 'comments', id, 'D', GETDATE(), 'NS', '', GETDATE(), usr, GETDATE(), usr from inserted
问题是当我一次更新多行时,它给出了以下错误:
消息 512,级别 16,状态 1,过程 cmt_update,第 17 行 [批处理开始 8号线]
子查询返回超过 1 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。
这个错误指的是这一行:
IF (select pendent from deleted) = 0 AND (select pendent from inserted) = 1
在搜索时我发现 SQL Server 触发器是按语句而不是按行执行的,只有在我更新多行时才会导致此错误。
我已经尝试了多种类似这样的解决方案,但都没有奏效:
IF (select pendent from comments c inner join deleted d on d.id = c.id) = 0 AND (select pendent from comments c inner join inserted i on i.id = c.id) = 1
我找到的解决方案都不像我的示例,因为触发器仅在我比较值时才会中断,因为两个插入的代码都具有正确的语法。
我发现使用游标可能会有所帮助,但我无法使代码正确地使用它,有人可以帮助我吗?谢谢!
【问题讨论】:
-
(select pendent from deleted) = 0和(select pendent from inserted) = 1;如果你UPDATE超过 1 行怎么办? -
这就是重点。代码在那里中断,因为我发现 SQL Server 触发器是语句级而不是行级。我写的触发器就像是行级的,我想知道当我们更新超过 1 行时如何在语句级实现相同的结果
-
“我编写的触发器就像是行级的” 这就是问题所在,每个 DML 语句都会“触发”一次触发器,而不是受DML 语句。但是,如果不真正知道您要在这里实现什么,这很难猜到。我们没有样本数据,没有涉及的其他对象的 DDL,也没有预期的行为结果。我的猜测是你需要一个
INSERT和一个WHERE,而不是一个INSERT前面有一个IF。 -
该表有一个名为pendent的列。当此列从 0 更改为 1 时,我想取消第二个 INSERT 语句
-
“dispult”?这是什么意思?
标签: sql sql-server triggers