SQL变量拼接表行字符串的执行逻辑及写法结果差异问题
SQL变量拼接场景执行逻辑解释
以下解释基于T-SQL(SQL Server)语法环境,对应给出的测试数据和语句:
基础测试数据
表names的name字段共有5行值,分别为s/r/i/n/u,查询语句:
select name from names
返回结果:
s r i n u
问题1:查询1未使用WHILE循环,为何能拼接所有表行数据?
查询1的语句如下:
declare @var varchar(20) set @var='' select @var=@var+name+',' from names select @var
返回结果为s,r,i,n,u,,核心原因是T-SQL中SELECT对变量赋值的隐式逐行迭代规则:
- 当
SELECT赋值语句的右侧表达式引用了被赋值变量本身时,查询引擎遍历结果集的每一行时,都会先取变量当前存储的旧值,和当前行的字段做计算,再把计算结果重新赋值给变量,整个过程不需要显式写WHILE循环,等价于隐式完成了逐行累加。
查询1的逐行执行过程:
- 初始通过
set @var=''把变量设为空字符串 - 遍历第一行(name='s'):计算
'' + 's' + ',' = 's,',赋值给@var,当前@var值为s, - 遍历第二行(name='r'):取当前@var值
s,,计算s, + 'r' + ',' = 's,r,',回写@var - 后续行依次重复上述拼接逻辑,直到遍历完最后一行name='u',最终@var值为
s,r,i,n,u,
注意:这种隐式拼接的结果顺序依赖执行计划的行扫描顺序,官方没有明确保证该行为的输出稳定性,生产环境做字符串聚合建议优先使用官方提供的
STRING_AGG等标准聚合函数。
问题2:查询2直接赋值空字符串拼接字段,为何结果和查询1完全不同?
查询2的语句如下:
declare @var varchar(20) select @var=''+name+',' from names select @var
返回结果为u,,核心原因是赋值逻辑没有累加,只有逐行覆盖:
- 该语句的赋值表达式右侧没有引用@var本身的旧值,每遍历一行,都会直接把当前行计算出的结果直接覆盖写入@var,之前行的赋值结果会被完全丢弃。
查询2的逐行执行过程:
- 变量声明后未设置初始值,默认值为NULL
- 遍历第一行(name='s'):计算
'' + 's' + ',' = 's,',直接覆盖@var,当前值为s, - 遍历第二行(name='r'):计算
'' + 'r' + ',' = 'r,',覆盖@var,当前值为r, - 后续每一行都重复覆盖逻辑,直到遍历完最后一行name='u',@var最终被覆盖为
u,,和查询1的累加逻辑有本质区别。
内容的提问来源于stack exchange,提问作者srini
相关产品推荐
相关产品推荐

