如何在多行且不带逗号的情况下使用 COALESCE?

use*_*180 30 sql-server t-sql

我正在努力实现以下目标:

California | Los Angeles, San Francisco, Sacramento
Florida    | Jacksonville, Miami
Run Code Online (Sandbox Code Playgroud)

不幸的是,我得到了“,洛杉矶,旧金山,萨克拉门托,杰克逊维尔,迈阿密”

我可以使用 STUFF 函数实现我想要的结果,但想知道是否有使用 COALESCE 更简洁的方法?

STATE       | CITY
California  | San Francisco
California  | Los Angeles
California  | Sacramento
Florida     | Miami
Florida     | Jacksonville 


DECLARE @col NVARCHAR(MAX);
SELECT @col= COALESCE(@col, '') + ',' + city
FROM tbl where city = 'California';
SELECT @col;
Run Code Online (Sandbox Code Playgroud)

谢谢

Aar*_*and 48

这可能是您所追求的更清洁的方法。基本上,检查变量是否已初始化。如果没有,请将其设置为空字符串,并附加第一个城市(无前导逗号)。如果有,则附加一个逗号,然后附加城市。

DECLARE @col nvarchar(MAX);
SELECT @col = COALESCE(@col + ',', '') + city
  FROM dbo.tbl WHERE state = 'California';
Run Code Online (Sandbox Code Playgroud)

当然,这仅适用于为每个状态填充变量。如果您一次为每个状态拉一个列表,则有一个更好的解决方案:

SELECT [state], cities = STUFF((
    SELECT N', ' + city FROM dbo.tbl
    WHERE [state] = x.[state]
    FOR XML PATH(''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 2, N'')
FROM dbo.tbl AS x
GROUP BY [state]
ORDER BY [state];
Run Code Online (Sandbox Code Playgroud)

结果:

DECLARE @col nvarchar(MAX);
SELECT @col = COALESCE(@col + ',', '') + city
  FROM dbo.tbl WHERE state = 'California';
Run Code Online (Sandbox Code Playgroud)

要按每个州内的城市名称排序:

SELECT [state], cities = STUFF((
    SELECT N', ' + city FROM dbo.tbl
    WHERE [state] = x.[state]
    ORDER BY city
    FOR XML PATH(''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 2, N'')
FROM dbo.tbl AS x
GROUP BY [state]
ORDER BY [state];
Run Code Online (Sandbox Code Playgroud)

在 Azure SQL 数据库或 SQL Server 2017+ 中,您可以使用STRING_AGG()功能

SELECT [state], cities = STRING_AGG(city, N', ')
  FROM dbo.tbl
  GROUP BY [state]
  ORDER BY [state];
Run Code Online (Sandbox Code Playgroud)

并按城市名称排序:

SELECT [state], cities = STRING_AGG(city, N', ') 
                         WITHIN GROUP (ORDER BY city)
  FROM dbo.tbl
  GROUP BY [state]
  ORDER BY [state];
Run Code Online (Sandbox Code Playgroud)

  • @user2732180 您应该使用 GROUP BY,因为它更有可能为每个状态执行一次连接。例如,使用 DISTINCT 它将对加利福尼亚的每个实例应用相同的串联,然后才丢弃它为生成这些重复所做的所有工作。 (2认同)

小智 7

只是为了补充上面亚伦的答案......

请注意,ORDER BY仅包含查询中的最后一项可能会中断。就我而言,我没有分组,所以不确定这是否有所不同。我正在使用 SQL 2014。在我的例子中,我有类似 value1、value2、value3 的东西......但我在变量中的结果只是 value3。


亚伦评论说:

这已在 Connect 上至少报告了四次:

  1. 在过滤器结果的变量连接和排序中(如 where 条件)
  2. (n) 当添加 ORDER BY 时,从 ResultSet 构建 varchar 失败
  3. 从带有 CROSS APPLY 和表值函数的有序 SELECT 中分配局部变量仅返回最后一个值
  4. 连接表变量中的 varchar(max)/nvarchar(max) 值时,如果按非主键列进行过滤和排序,则可能会返回不正确的结果

来自 Microsoft 的示例响应:

您看到的行为是设计使然。在带有 ORDER BY 子句的查询中使用赋值操作(在此示例中为串联)具有未定义的行为。

响应还引用了 KB 287515:

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

FOR XML PATH如果串联顺序很重要,当然,如果您想确保包含所有值,则解决方案是使用(Aaron 答案中的第二种方法)。另见:

nvarchar 连接/索引/nvarchar(max)堆栈上的莫名其妙的行为