使用变量 Coalesce 排序

Order by with variable Coalesce

我有以下 sql 命令

DECLARE @cols NVARCHAR (MAX)
SELECT @cols = COALESCE (@cols + ',['+ cast(Month as nvarchar(2))+']' , '['+ Cast(Month as nvarchar(2))+']')
FROM    (select distinct Month from Employee  WHERE  Year*100+Month BETWEEN 201704 and 201712 ) as e
PRINT @cols 

结果是

[9],[12],[6],[7],[10],[4],[5],[11],[8]

但我真的希望它按排序顺序排列

[4],[5],[6],[7],[8],[9],[10],[11],[12]

变量合并 is documented as being non-deterministic, and may cause incorrect results,特别是在存在 ORDER BY 的情况下。您也不能将 ORDER BY 放在派生的 table 或视图中,原因很明显:最终排序 由外部查询确定。

您应该改为只使用 STRING_AGG 进行聚合。您可以使用 WITHIN GROUP (ORDER BY 来获取顺序。

另请注意:

  • 始终使用 QUOTENAME 将列名括起来,而不是自己动手,因为转义可能很复杂。
  • 最好对列进行精确比较,而不是对它们进行计算然后比较,因为这样您就可以命中索引(sarge-ability)。
  • 最好将日期存储在实际的日期列中,而不是乱用多个列,但我会将数据库重新设计留给您
DECLARE @cols NVARCHAR(MAX) = (
    SELECT STRING_AGG(QUOTENAME(Month), N',') WITHIN GROUP (ORDER BY Month)
    FROM (
        select distinct
          Month
        from Employee
        WHERE Year = 2017
          AND Month BETWEEN 4 AND 12
    ) as e
);

对于 SQL Server 2016 及更早版本,您可以使用旧的 FOR XML 方法:

DECLARE @cols NVARCHAR(MAX) = STUFF((
    SELECT N',' + QUOTENAME(Month)
    FROM (
        select distinct
          Month
        from Employee
        WHERE Year = 2017
          AND Month BETWEEN 4 AND 12
    ) as e
    ORDER BY Month
    FOR XML PATH(''), TYPE
  ).value('text()[1]','nvarchar(max)')
  , 1, LEN(N','), N'');