+ =在SELECT子句中; 常数vs列

Ind*_*942 9 sql t-sql sql-server sql-server-2017

我在MS SQL Server 2017中观察到了一些奇怪的行为.

  • +=在select中充当聚合器('连接所有行的值'),当右边是常量时.
  • +=在select中,当右侧是列名时,则表示"只设置值" .(另外,这会改变其他列的聚合行为)

所以我的问题是:

  1. 为什么@c1结果只包含最后一行的值,即使+=使用了?
  2. 为什么@c2受到影响,通过改变+=- > =@c1

版本1:

BEGIN
    DECLARE
        @c1 NVARCHAR(MAX) = N'',
        @c2 NVARCHAR(MAX) = N'';

    SELECT
        @c1 = constraint_name, -- version-1
        @c2 += '+'
    FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS
    ORDER BY 1 DESC
    ;

    PRINT '@c1=' + @c1;
    PRINT '@c2=' + @c2;
END
;
Run Code Online (Sandbox Code Playgroud)

版本1结果:

@c1 = fk_abcde
@c2 = ++++++++++++++++++++++++++++++++++++++++++
(`@c2` result is aggregation of many rows; one plus for each row)
Run Code Online (Sandbox Code Playgroud)

版本2:

BEGIN
    DECLARE
        @c1 NVARCHAR(MAX) = N'',
        @c2 NVARCHAR(MAX) = N'';

    SELECT
        @c1 += constraint_name, -- version-2
        @c2 += '+'
    FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS
    ORDER BY 1 DESC
    ;

    PRINT '@c1=' + @c1;
    PRINT '@c2=' + @c2;
END
;
Run Code Online (Sandbox Code Playgroud)

版本2结果:

@c1 = fk_abcde
@c2 = +
(`@c2` is just value assigned from last processed row)
Run Code Online (Sandbox Code Playgroud)

这感觉很奇怪 - 有点像虫子.我没有找到任何关于此的文档.'+ = string'上文档根本没有提到查询中的+=用法select.

(目前我的目标是完全理解这种行为,所以我不会不小心踩到它.任何有关正确的文档/关键字搜索的提示都会有所帮助)

Dam*_*ver 2

在文档中的位置错误,因此您没有找到它也就不足为奇了:

不要在 SELECT 语句中使用变量来连接值(即计算聚合值)。可能会出现意外的查询结果。因为,SELECT 列表中的所有表达式(包括赋值)不一定对每个输出行运行一次

最好寻找不同的字符串连接方法。如果您的版本支持,请选择使用STRING_AGG. 对于早期版本,Aaron Bertrand 提供了一组很好的选项(感谢 Panagiotis Kanavos提供的链接