You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CONCAT函数为变量赋值时出现意外聚合的原因咨询

CONCAT赋值变量时意外聚合的原因解析

当使用CONCAT(或CONCAT_WS)将查询结果赋值给仅声明但未初始化的变量时,会出现意外的字符串聚合效果,而非仅保留最后一行的赋值结果,以下是具体分析:

测试代码与执行结果

测试SQL代码

CREATE TABLE #test(val varchar(10))
INSERT INTO #test SELECT * FROM string_split('A|B|C', '|')
DECLARE @str1a nvarchar(4000), @str1b nvarchar(4000), @str2 nvarchar(4000), @str3 nvarchar(4000)
SELECT @str1a = CONCAT(@str1a,  val) FROM #test; PRINT @str1a;
SELECT @str1b = CONCAT(val, @str1b) FROM #test; PRINT @str1b;
SELECT @str2 = CONCAT(NULL,  val) FROM #test; PRINT @str2;
SELECT @str3 = CONCAT('',  val) FROM #test; PRINT @str3;
DROP TABLE #test

执行结果

(影响3行)
ABC
CBA
C
C

原因分析

  1. 未初始化变量的默认值是NULL
    声明但未赋值的SQL变量初始值为NULL,这是核心前提。

  2. CONCAT函数对NULL的处理逻辑
    CONCAT函数会自动忽略所有NULL参数,只拼接非NULL的内容。当执行SELECT @str1a = CONCAT(@str1a, val)时,SQL Server会逐行遍历表中数据,并依次执行赋值操作:

    • 第一行:CONCAT(NULL, 'A') 结果为'A',@str1a被赋值为'A'
    • 第二行:CONCAT('A', 'B') 结果为'AB',@str1a被更新为'AB'
    • 第三行:CONCAT('AB', 'C') 结果为'ABC',@str1a最终变为'ABC'
      @str1b = CONCAT(val, @str1b) 的逻辑同理,只是拼接顺序相反,最终得到倒序的'CBA'。
  3. 非累加场景的差异
    当执行SELECT @str2 = CONCAT(NULL, val)时,每次都是用固定的NULL和当前行的val拼接,结果始终等于当前行的val,但赋值操作是逐行覆盖变量值,最终变量会保留最后一行的结果'C';CONCAT('', val)的逻辑类似,空字符串和val拼接结果还是val,同样逐行覆盖后得到最后一行的'C'。

  4. 注意事项
    这种逐行赋值实现聚合的方式属于SQL Server的非预期行为,官方并不推荐依赖该逻辑实现字符串聚合——因为执行计划的变化可能导致结果不符合预期。若需要正规的字符串聚合,建议使用STRING_AGG函数(SQL Server 2017及以上版本)。

内容的提问来源于stack exchange,提问作者SirParser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 07:53:21