【问题标题】:SQL Server trigger in value comparison: Subquery returned more than 1 value值比较中的 SQL Server 触发器:子查询返回超过 1 个值
【发布时间】: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


【解决方案1】:

在黑暗中刺伤但是......:

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',
       i.id,
       'D',
       GETDATE(),
       'NS',
       '',
       GETDATE(),
       i.usr,
       GETDATE(),
       i.usr
FROM inserted i
     JOIN deleted d ON i.YourIDColumn = d.YourIdColumn
WHERE i.pendent = 1
  AND d.pendent = 0;

【讨论】:

  • 是的!这正是我想要的!我非常感谢您为理解问题并帮助我找到解决问题的方法所做的努力。谢谢!
【解决方案2】:

错误是野兔:IF (select pendent from deleted) = 0 AND (select pendent from inserted) = 1 您需要使用类似 `IF 存在(从已删除的 pendent = 0 中选择 pendent)和(从已删除的 pendent = 0 中选择 pendent)

继续享受……

【讨论】:

  • 这不太可能给出预期的结果; OP 正在检查值是否已从 0 更改为 1 for pendent。如果没有任何行的 pendent 的值发生变化,但 至少 1 的值为 1 且至少有一个值为 0,它会是 INSERT all 受 DML 语句影响的行,即使不应该是。
猜你喜欢
  • 2022-01-17
  • 2013-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多