SQL Server两种标量变量赋值语法的差异及报错逻辑疑问
两种SQL变量赋值语法的差异解析
问题场景
原本假设MySourceTable表的Period字段值唯一,使用以下方式给int类型变量@tarih赋值:
SET NOCOUNT ON; DECLARE @tarih INT; ------------ SELECT @tarih = Dates FROM ( SELECT DISTINCT [Period] AS Dates FROM MySourceTable STG WITH(NOLOCK) ) a
但当表返回多个Period值时,SQL Server并未报错,而是将结果集中的最后一个值赋值给变量。
改用以下写法时,多值场景下会按预期抛出错误:
DECLARE @tarih INT; ------------ SELECT @tarih = ( SELECT DISTINCT [Period] FROM MySourceTable STG WITH(NOLOCK) )
错误信息:
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression.
语法与运行机制差异
1. 第一种写法:行集遍历式赋值
这种写法的本质是逐行遍历结果集,反复覆盖变量值:
- SQL Server先执行内层的
DISTINCT查询得到结果集,然后逐行将Dates列的值赋给@tarih,每一行都会替换变量的当前值。 - 最终变量存储的是结果集的最后一行值,但注意:如果没有显式添加
ORDER BY,结果集的行顺序是不确定的,所以最终赋值的结果也不可预测。 - 这种语法最初是为配合聚合函数(如
SUM、COUNT)做聚合赋值设计的,直接赋值单列时就会变成逐行覆盖的行为,SQL Server不会校验结果集的行数,因此返回多行也不会报错。
2. 第二种写法:标量子查询赋值
这种写法要求右侧的子查询必须是标量子查询(仅返回单行单列):
- 当使用
SELECT @变量 = (子查询)的形式时,SQL Server会强制校验子查询的返回结果:如果返回多行,直接触发错误,因为标量表达式不允许存在多个值。 - 这种语法的设计目的是明确要求赋值的是单个确定值,属于严格的单值赋值场景,不符合条件就会报错。
核心区别总结
- 行集遍历赋值:允许结果集多行,最终取最后一行值(无报错),逻辑是逐行覆盖变量
- 标量子查询赋值:强制要求结果集单行,多行直接报错,逻辑是校验单值表达式合法性
内容的提问来源于stack exchange,提问作者Halil
相关产品推荐
相关产品推荐

