Order by 1 将结果集缩短为一行

Hen*_*sen 3 sql-server order-by sql-server-2016

我正在运行以下查询:

DECLARE @sql NVARCHAR(max) = N''
SELECT @sql += N' EXEC dbo.DoSomething @Tablename = ''' + SCHEMA_NAME(T.schema_id) + N'.' + T.name + N''''
--SELECT * 
FROM sys.tables T
INNER JOIN sys.indexes I ON I.object_id = T.object_id
ORDER by 1 
PRINT  @sql
Run Code Online (Sandbox Code Playgroud)

但我只打印了一行。如果我取出这ORDER by 1条线,或者用它替换它,
ORDER BY t.name那么我就会得到预期的结果。

这是 SQL Server 中的错误吗?
我已经在 SQL Server 2016 SP1 和 2014 Sp2-Cu1 上试过了。

Mik*_*son 6

这是 SQL Server 中的错误吗?

不。

来自PRB:聚合串联查询的执行计划和结果取决于表达式位置

聚合串联查询的正确行为未定义。

另请参阅Martin Smith在 stackoverflow 上的出色回答。 nvarchar 连接/索引/nvarchar(max) 莫名其妙的行为

有时它有效,有时它不起作用,这取决于执行计划。如果将执行连接的计算标量定位为 select 运算符下方的第一个运算符,则魔术会起作用。

declare @T table(Name nvarchar(5));
insert into @T values (N'aaaa3'),(N'bbbb2'),(N'cccc1');
declare @S nvarchar(18) = N'';

select @S += ',' + T.Name
from @T as T;
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

但如果你不走运,你最终可能会有不同的计划。这个在选择和计算标量之间有一个排序运算符。

select @S += ',' + T.Name
from @T as T
order by reverse(T.Name);
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

解决这个问题的最好方法(在我看来)是使用for xml path来代替连接。

select @S  = (
             select ',' + T.Name 
             from @T as T
             order by reverse(T.Name)
             for xml path(''), type
             ).value('text()[1]', 'nvarchar(max)');
Run Code Online (Sandbox Code Playgroud)

将来某些版本的 SQL Server 将具有内置的字符串聚合函数STRING_AGG (Transact-SQL)