无嵌套子查询却触发Dapper子查询返回多值错误,求排查方案
别慌!你遇到的这个情况其实挺常见的——虽然你的SELECT * FROM dbo.someTable看起来完全没有子查询,但报错指向子查询返回多行,而且SSMS执行也出同样问题,这说明问题根本不在你的查询语句本身,而是在表本身的关联对象上。
下面是几个最可能的排查方向,按优先级来:
检查目标表上的触发器:很多时候,表上的触发器(哪怕是
INSERT/UPDATE触发器,有时候查询操作也可能触发某些逻辑)里可能包含了返回多行的子查询。比如触发器里用了WHERE column = (SELECT ...)这种写法,括号里的子查询如果返回多条结果,就会直接抛出这个错误。你可以用这段SQL快速查询表上的所有触发器定义:SELECT name, definition FROM sys.triggers WHERE parent_id = OBJECT_ID('dbo.someTable')仔细扫一遍触发器的逻辑,重点找那些用单行比较运算符(
=, !=, <, <=, >, >=)的子查询。确认
someTable是不是视图:如果dbo.someTable其实是一个视图,那视图的定义里很可能藏了子查询,或者视图关联的底层表有触发器。用下面的语句查看视图的完整定义:SELECT definition FROM sys.views WHERE name = 'someTable'检查视图的SQL逻辑,有没有子查询误用了单行比较符的情况。
排查表中的计算列:如果表中有计算列,计算列的表达式里如果包含了返回多行的子查询,当你执行
SELECT *的时候会自动计算这个列的值,也会触发这个错误。用这段SQL查看表的所有计算列:SELECT name, definition FROM sys.computed_columns WHERE object_id = OBJECT_ID('dbo.someTable')
我之前就遇到过类似的案例:用户的表上有一个AFTER SELECT触发器,里面写了SET @tempVar = (SELECT user_id FROM audit_log WHERE ...),但这个子查询返回了两条匹配记录,导致每次查询主表都会抛出这个“子查询返回多行”的错误,和你的情况一模一样。
总结一下:当你的查询语句本身没问题,但执行时抛出子查询相关错误,别死盯着自己的代码看,优先检查表的触发器、视图定义、计算列这些隐藏的逻辑——这些才是问题的根源。
内容的提问来源于stack exchange,提问作者Doruk

