SQLServer2019执行UPDATE报Subquery returned more than 1 value错误
问题根因
你遇到的报错和你写的两条UPDATE语句本身没有关系,触发错误的根本原因是Orders表上存在编写不规范的DML触发器。
这个判断的核心依据是:你写的第二条按固定值+IN条件更新的语句,语法上完全不存在会触发“子查询返回多值”的逻辑,这种场景下报这个错,100%是表上挂载的触发器在执行时出了问题。
SQL Server 2000环境下语句能正常运行,是因为旧版本引擎对触发器的批量数据适配校验宽松,很多遗留触发器默认假设每次UPDATE只影响单行,小数据量操作时碰巧不会触发子查询多返回值的问题;升级到2019版本后,引擎对DML执行链路的校验更严格,只要触发器内部的子查询返回多行,就会直接抛出你看到的错误,和外层更新逻辑无关。
定位步骤
首先执行以下语句查看Orders表上所有已启用的触发器,检查触发器内部逻辑:
SELECT name, OBJECT_DEFINITION(object_id) AS trigger_content FROM sys.triggers WHERE parent_id = OBJECT_ID('Orders') AND is_disabled = 0 AND type = 'TR'
你可以重点检查触发器里的两类常见错误写法:
- 用标量变量接收子查询结果时,没有加
TOP 1或关联条件不严谨,批量更新时子查询返回多行,比如SET @order_a = (SELECT a FROM inserted)这类写法 - 触发器内部的更新/赋值语句关联条件缺失,导致子查询没有按逐行匹配返回单值,比如
UPDATE log SET order_a = (SELECT a FROM inserted)这类没写关联条件的逻辑
你也可以用下面的方法快速验证判断:临时禁用表上所有触发器后执行你之前报错的UPDATE语句,如果能正常执行,就可以完全确认是触发器导致的问题。
-- 临时禁用Orders表所有触发器 DISABLE TRIGGER ALL ON Orders; -- 执行之前报错的测试更新语句 Update Orders Set a = 201 Where OrderID in (100286,100288,100293,100294,100296,100451,100461,100462,100467) -- 测试完成后记得重新启用触发器 ENABLE TRIGGER ALL ON Orders;
优化后的关联更新写法
等你修复完触发器的逻辑问题后,原来的跨表补数UPDATE可以简化成下面的写法,执行效率更高,也不会产生语义歧义:
UPDATE o1 SET o1.a = o2.a FROM Orders o1 INNER JOIN Orders2 o2 ON o1.OrderID = o2.OrderID WHERE o1.a IS NULL
注意提前确认Orders2表中OrderID是唯一键,避免一个OrderID对应多个不同a值导致的更新结果不确定问题。
内容的提问来源于stack exchange,提问作者James H
相关产品推荐
相关产品推荐

