【问题标题】:SQL: Concatenate column values in a single row into a string separated by commaSQL:将单行中的列值连接成以逗号分隔的字符串
【发布时间】:2012-07-06 06:08:15
【问题描述】:

假设我在 SQL Server 中有一个这样的表:

Id    City           Province             Country
1     Vancouver      British Columbia     Canada
2     New York       null                 null
3     null           Adama                null
4     null           null                 France
5     Winnepeg       Manitoba             null
6     null           Quebec               Canada
7     Seattle        null                 USA 

如何获得查询结果,以便位置是由“,”分隔的城市、省和国家/地区的串联,并省略空值。我想确保没有任何尾随逗号、前逗号或空字符串。例如:

Id    Location
1     Vancouver, British Columbia, Canada
2     New York
3     Adama
4     France
5     Winnepeg, Manitoba
6     Quebec, Canada
7     Seattle, USA

【问题讨论】:

  • 糟糕...删除了我的错误答案...没有仔细阅读
  • @AaronBertrand,你能指出我的重复吗?我花了很多时间寻找关于 SO 的答案,但找不到任何答案。
  • @SQLCurious,我已经尝试了很多东西,但很惊讶这比我想象的要困难得多。在另一种语言中,我会简单地使用类似 Array.Join(array, ", ") 的东西,但我在 SQL 中找不到任何类似的东西。你的评论让我相信你认为这是微不足道的,所以你能提供你的答案吗?
  • 谢谢@AaronBertrand

标签: sql-server tsql string-concatenation


【解决方案1】:

我认为这可以解决我在其他答案中发现的所有问题。无需测试输出的长度或检查前导字符是否为逗号,无需担心连接非字符串类型,在不可避免地添加其他列(例如邮政编码)时不会显着增加复杂性...

DECLARE @x TABLE(Id INT, City VARCHAR(32), Province VARCHAR(32), Country VARCHAR(32));

INSERT @x(Id, City, Province, Country) VALUES
(1,'Vancouver','British Columbia','Canada'),
(2,'New York' , null             , null   ),
(3, null      ,'Adama'           , null   ),
(4, null      , null             ,'France'),
(5,'Winnepeg' ,'Manitoba'        , null   ),
(6, null      ,'Quebec'          ,'Canada'),
(7,'Seattle'  , null             ,'USA'   );

SELECT Id, Location = STUFF(
      COALESCE(', ' + RTRIM(City),     '') 
    + COALESCE(', ' + RTRIM(Province), '') 
    + COALESCE(', ' + RTRIM(Country),  '')
    , 1, 2, '')
  FROM @x;

SQL Server 2012 添加了一个名为 CONCAT 的新 T-SQL 函数,但它在这里没有用处,因为您仍然必须选择在发现的值之间包含逗号,并且没有工具可以做到这一点 - 它只是消除值加上没有分隔符的选项。这避免了担心非字符串类型,但不允许您非常优雅地处理空值与非空值。

【讨论】:

  • 非常感谢您……这真的帮助了我
  • 很好的答案,谢谢 - 我还需要一个空字符串检查,使用 NULLIF,所以:SELECT Id, Location = STUFF( COALESCE(', ' + RTRIM(NULLIF(City,'')), '') + COALESCE(', ' + RTRIM(NULLIF(Province,'')), '') + COALESCE(', ' + RTRIM(NULLIF(Country,'')), '') , 1, 2, '') FROM @x;
【解决方案2】:
select Id ,   
 Coalesce( City + ',' +Province + ',' + Country,
           City+ ',' + Province,
           Province + ',' + Country,
           City+ ',' + Country,
           City,
           Province,
           Country
          ) as location
from table

【讨论】:

  • 请注意,应将 CONCAT_NULL_YIELDS_NULL 设置为启用此功能。解决问题的好方法。
  • 我觉得我一点也不优雅。如果有 5 列、9 列或 15 列怎么办?你真的要列出所有可能的组合吗?哎呀。
  • 我实际上同意@AaronBertrand 我的解决方案可以解决这个问题,但它不能很好地扩展。他在问题下的评论中链接到的公认答案效果更好。
  • 当列数更多时会出现问题,而且这里有大约 7 个检查三列组合如果没有列增加怎么办.....
【解决方案3】:

这是一个难题,因为逗号必须放在中间:

select id, coalesce(city+', ', '')+coalesce(province+', ', '')+coalesce(country, '')
from t

似乎它应该可以工作,但我们可以在末尾得到一个无关的逗号,例如当国家为 NULL 时。所以,它需要更复杂一点:

select id,
       (case when right(val, 2) = ', ' then left(val, len(val) - 1)
             else val
        end) as val
from (select id, coalesce(city+', ', '')+coalesce(province+', ', '')+coalesce(country, '') as val
      from t
     ) t

没有太多的中间逻辑,我觉得最简单的方法是给每个元素加一个逗号,然后把多余的逗号去掉。

【讨论】:

  • 这会产生例如New YorWinnipeg, Manitob
  • 糟糕,SQL Server 忽略字符串末尾的空格。所以“-2”也删除了最后一个字符。我把它改成了“- 1”。
  • 它仍然是不必要的复杂(至少恕我直言)。您认为这里需要子查询还是需要检查尾随字符?
  • 对我来说,这个逻辑比你的版本更容易理解,因为逗号自然出现在单词之后,而不是在它们之前。除此之外,它们本质上是相同的(我之前实际上考虑过用逗号来做,但对我来说看起来很尴尬)。你的优点是你不需要知道逗号在哪里删除它,因为它总是在开头。
  • 我认为引入子查询是为了在列名之后放置逗号而不是以前的复杂性。 YMMV。
【解决方案4】:

使用“+”运算符。

了解 null 值不适用于 '+' 运算符(例如:'Winnepeg' + null = null),因此请务必使用 ISNULL() 或 COALESCE() 函数将 null 替换为空字符串,例如:ISNULL('Winnepeg','') + ISNULL(null,'')。

此外,如果您的某个列可能被解释为数字,那么请务必同时使用 CAST() 函数,以避免错误返回,例如:CAST('Winnepeg'作为 varchar(100))。

到目前为止,大多数示例都忽略了其中的一个或多个部分。此外——一些示例使用子查询或进行长度检查,你真的不应该这样做——只是没有必要——尽管如果你这样做,你的优化器可能会救你。

祝你好运

【讨论】:

  • +1 这是除我之外我能同意的唯一答案,不幸的是您没有包含任何代码。 :-\
【解决方案5】:

很难看,但它适用于 MS SQL:

    select
    id,
    case
        when right(rtrim(coalesce(city + ', ','') + coalesce(province + ', ','') + coalesce(country,'')),1)=',' then left(rtrim(coalesce(city + ', ','') + coalesce(province + ', ','') + coalesce(country,'')),LEN(rtrim(coalesce(city + ', ','') + coalesce(province + ', ','') + coalesce(country,'')))-1)
        else rtrim(coalesce(city + ', ','') + coalesce(province + ', ','') + coalesce(country,''))
    end
from
    table

【讨论】:

  • 这没有错,但它非常复杂。还要考虑当有 4、5 或 6 列时,Kevin 的答案会有多复杂。
【解决方案6】:

这是一个选项:

SELECT (CASE WHEN City IS NULL THEN '' ELSE City + ', ' END) + 
(CASE WHEN Province IS NULL THEN '' ELSE Province + ', ' END) +
(CASE WHEN Country IS NULL THEN '' ELSE Country END) AS LOCATION
FROM MYTABLE

【讨论】:

  • 如果 City 为空,您将获得, Quebec, Canada。我不想要前面的逗号。
  • 更新为 NULL 城市
  • 仍然留下逗号,例如Winnipeg, Manitoba,
猜你喜欢
  • 2016-03-13
  • 2012-12-22
  • 2021-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-29
相关资源
最近更新 更多