对用 STUFF 生成的逗号分隔字符串的结果进行排序

McN*_*ets 5 sql-server order-by csv

给定这样的架构:

CREATE TABLE Foo
(
    Id int PRIMARY KEY,
    Position int NOT NULL,
    Title varchar(10) NOT NULL
);

INSERT INTO Foo VALUES
(1, 3,  'Title3'),
(2, 10, 'Title10'),
(3, 1,  'Title1'),
(4, 12, 'Title12'),
(5, 2,  'Title2');
Run Code Online (Sandbox Code Playgroud)

我需要生成一个逗号分隔的字符串,按Position以下顺序排序:

'M' + Id + ' AS [' + Title + ']'
Run Code Online (Sandbox Code Playgroud)

想要的结果:

M1 AS [Title1], M2 AS [Title10], M3 AS [Title3], M4 AS [Title10], M5 AS [Title12]
Run Code Online (Sandbox Code Playgroud)

我试过了:

DECLARE @rows nvarchar(max);
SET @rows = STUFF((SELECT DISTINCT ', ' + ('M' + CAST(Id as varchar(10)) + ' AS ' + QUOTENAME(Title)) 
                   FROM Foo
            FOR XML PATH(''), TYPE
            ).value('.', 'nvarchar(MAX)') 
           ,1,1,'');

SELECT @rows;
Run Code Online (Sandbox Code Playgroud)

但它构建按以下顺序排列的结果Id

M1 AS [Title3], M2 AS [Title10], M3 AS [Title1], M4 AS [Title12], M5 AS [Title2]
Run Code Online (Sandbox Code Playgroud)

如果我添加ORDER BY IdSTUFF表达式:

DECLARE @rows nvarchar(max);
SET @rows = STUFF((SELECT DISTINCT ', ' + ('M' + CAST(Id as varchar(10)) + ' AS ' + QUOTENAME(Title)) 
                   FROM Foo
                   ORDER BY Position
            FOR XML PATH(''), TYPE
            ).value('.', 'nvarchar(MAX)') 
           ,1,1,'');

SELECT @rows;
Run Code Online (Sandbox Code Playgroud)

产生下一个错误:

Msg 145 Level 15 State 1 Line 2
ORDER BY 项必须出现在选择列表中,如果指定了 SELECT DISTINCT。+

我可以使用按以下顺序排序的子查询Position

DECLARE @rows nvarchar(max);
SET @rows = STUFF((SELECT DISTINCT ', ' + ('M' + CAST(Id as varchar(10)) + ' AS ' + QUOTENAME(Title)) 
                   FROM (SELECT TOP 100 PERCENT Id, Position, Title FROM Foo ORDER BY Position) X
            FOR XML PATH(''), TYPE
            ).value('.', 'nvarchar(MAX)') 
           ,1,1,'');

SELECT @rows;

M1 AS [Title3], M2 AS [Title10], M3 AS [Title1], M4 AS [Title12], M5 AS [Title2]
Run Code Online (Sandbox Code Playgroud)

但我想知道是否有另一种方法可以在不使用子查询的情况下对结果进行排序。没有重复的标题。

dbfiddle在这里

McN*_*ets 3

正如Aaron Bertrand在评论中指出的那样,产生错误是因为我正在使用SELECT DISTINCT; 在这个例子中,这是没有必要的。此外,ORDER BY如果删除了不同值,则位置完全有效。

如果DISTINCT删除,查询将返回所需的值:

DECLARE @rows nvarchar(max);
SET @rows = STUFF((SELECT ', ' + ('M' + CAST(Id as varchar(10)) + ' AS ' + QUOTENAME(Title)) 
                   FROM Foo
                   ORDER BY Position
            FOR XML PATH(''), TYPE
            ).value('.', 'nvarchar(MAX)') 
           ,1,1,'');

SELECT @rows;
GO
Run Code Online (Sandbox Code Playgroud)
| (无列名)|
| :---------------------------------------------------------------- ------------------------------------------- |
| M3 AS [标题 1]、M5 AS [标题 2]、M1 AS [标题 3]、M2 AS [标题 10]、M4 AS [标题 12] |

dbfiddle在这里

我建议看一下sp_BlitzErik推荐的这篇文章:

分组串联:排序和删除重复项