+= 在 SELECT 子句中;常量与列
+= in SELECT clause; constant vs column
我在 MS SQL Server 2017 中观察到一些奇怪的行为。
+=
在 select 中作为聚合器 ('concatenate values from all rows') 当右边是一个 constant.
select 中的 +=
当右边是 列名称 时充当 'just set the value'。 (另外,这轮到其他列的聚合行为)
所以我的问题是:
- 为什么
@c1
结果只包含最后一行的值,即使使用 +=
也是如此?
- 为什么
@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
;
版本 1 结果:
@c1 = fk_abcde
@c2 = ++++++++++++++++++++++++++++++++++++++++++
(`@c2` result is aggregation of many rows; one plus for each row)
版本 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
;
版本 2 结果:
@c1 = fk_abcde
@c2 = +
(`@c2` is just value assigned from last processed row)
这感觉很奇怪 - 有点像错误。
我找不到任何关于此的文档。
doc on '+= string' 根本没有在 select
查询中提及 +=
用法。
(目前我的目标是完全理解这个行为,所以我不会不小心踩到它。任何向右 documentation/keywords 搜索的提示都会有所帮助)
您应该使用 Order by constraint_name
而不是 Order by 1
,因为您正在为变量赋值。它不是 select 声明。
好吧,我的发现很有趣:没有 ORDER BY
查询运行一致且符合预期。
但是当加上 ORDER BY
因果关系时,我得到的结果和你一样。
我的建议是使用 CTE 进行排序 - 不幸的是,CTE 或子查询中不允许排序,但解决方法是使用 TOP
关键字,它允许我们在这种情况下进行排序。
参见下面的脚本:
;with cte as (
select top 100 percent table_schema
from information_schema.columns
order by 1
)
-- This is more reliable
select @c1 = table_schema, @c2 += '+' from cte
它在 wrong place in the documentation 中,所以您找不到它也就不足为奇了:
Don't use a variable in a SELECT statement to concatenate values (that is, to compute aggregate values). Unexpected query results may occur. Because, all expressions in the SELECT list (including assignments) aren't necessarily run exactly once for each output row
最好寻找不同的字符串连接方法。如果你的版本支持,选择使用STRING_AGG
。对于早期版本,Aaron Bertrand 提供了 good set of options (hat tip to Panagiotis Kanavos for )
我在 MS SQL Server 2017 中观察到一些奇怪的行为。
+=
在 select 中作为聚合器 ('concatenate values from all rows') 当右边是一个 constant.
select 中的 +=
当右边是 列名称 时充当 'just set the value'。 (另外,这轮到其他列的聚合行为)
所以我的问题是:
- 为什么
@c1
结果只包含最后一行的值,即使使用+=
也是如此? - 为什么
@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
;
版本 1 结果:
@c1 = fk_abcde
@c2 = ++++++++++++++++++++++++++++++++++++++++++
(`@c2` result is aggregation of many rows; one plus for each row)
版本 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
;
版本 2 结果:
@c1 = fk_abcde
@c2 = +
(`@c2` is just value assigned from last processed row)
这感觉很奇怪 - 有点像错误。
我找不到任何关于此的文档。
doc on '+= string' 根本没有在 select
查询中提及 +=
用法。
(目前我的目标是完全理解这个行为,所以我不会不小心踩到它。任何向右 documentation/keywords 搜索的提示都会有所帮助)
您应该使用 Order by constraint_name
而不是 Order by 1
,因为您正在为变量赋值。它不是 select 声明。
好吧,我的发现很有趣:没有 ORDER BY
查询运行一致且符合预期。
但是当加上 ORDER BY
因果关系时,我得到的结果和你一样。
我的建议是使用 CTE 进行排序 - 不幸的是,CTE 或子查询中不允许排序,但解决方法是使用 TOP
关键字,它允许我们在这种情况下进行排序。
参见下面的脚本:
;with cte as (
select top 100 percent table_schema
from information_schema.columns
order by 1
)
-- This is more reliable
select @c1 = table_schema, @c2 += '+' from cte
它在 wrong place in the documentation 中,所以您找不到它也就不足为奇了:
Don't use a variable in a SELECT statement to concatenate values (that is, to compute aggregate values). Unexpected query results may occur. Because, all expressions in the SELECT list (including assignments) aren't necessarily run exactly once for each output row
最好寻找不同的字符串连接方法。如果你的版本支持,选择使用STRING_AGG
。对于早期版本,Aaron Bertrand 提供了 good set of options (hat tip to Panagiotis Kanavos for