如何使用 GROUP BY 在 SQL Server 中连接字符串?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/273238/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-01 00:12:05  来源:igfitidea点击:

How to use GROUP BY to concatenate strings in SQL Server?

sqlsql-serverstring-concatenationsql-server-group-concat

提问by Eldila

How do I get:

如何得到:

id       Name       Value
1          A          4
1          B          8
2          C          9

to

id          Column
1          A:4, B:8
2          C:9

回答by Kevin Fairchild

No CURSOR, WHILE loop, or User-Defined Function needed.

不需要 CURSOR、WHILE 循环或用户定义的函数

Just need to be creative with FOR XML and PATH.

只需要对 FOR XML 和 PATH 发挥创意。

[Note: This solution only works on SQL 2005 and later. Original question didn't specify the version in use.]

[注意:此解决方案仅适用于 SQL 2005 及更高版本。原始问题没有指定使用的版本。]

CREATE TABLE #YourTable ([ID] INT, [Name] CHAR(1), [Value] INT)

INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'A',4)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'B',8)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (2,'C',9)

SELECT 
  [ID],
  STUFF((
    SELECT ', ' + [Name] + ':' + CAST([Value] AS VARCHAR(MAX)) 
    FROM #YourTable 
    WHERE (ID = Results.ID) 
    FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
  ,1,2,'') AS NameValues
FROM #YourTable Results
GROUP BY ID

DROP TABLE #YourTable

回答by Kannan Kandasamy

If it is SQL Server 2017 or SQL Server Vnext, SQL Azure you can use string_agg as below:

如果是 SQL Server 2017 或 SQL Server Vnext, SQL Azure 你可以使用 string_agg 如下:

select id, string_agg(concat(name, ':', [value]), ', ')
    from #YourTable 
    group by id

回答by Allen

using XML path will not perfectly concatenate as you might expect... it will replace "&" with "&amp;" and will also mess with <" and ">...maybe a few other things, not sure...but you can try this

使用 XML 路径不会像您预期的那样完美连接……它将用“&”替换“&” 并且还会弄乱<" and ">......也许还有其他一些事情,不确定......但你可以试试这个

I came across a workaround for this... you need to replace:

我遇到了一个解决方法......你需要更换:

FOR XML PATH('')
)

with:

和:

FOR XML PATH(''),TYPE
).value('(./text())[1]','VARCHAR(MAX)')

...or NVARCHAR(MAX)if thats what youre using.

...或者NVARCHAR(MAX)如果那是你正在使用的。

why the hell doesn't SQLhave a concatenate aggregate function? this is a PITA.

为什么地狱没有SQL连接聚合函数?这是一个皮塔饼。

回答by Jonathan Sayce

I ran into a couple of problems when I tried converting Kevin Fairchild's suggestion to work with strings containing spaces and special XML characters (&, <, >) which were encoded.

当我尝试将 Kevin Fairchild 的建议转换为使用包含空格和特殊 XML 字符(&, <, >)的字符串时,我遇到了一些问题。

The final version of my code (which doesn't answer the original question but may be useful to someone) looks like this:

我的代码的最终版本(它没有回答原始问题,但可能对某人有用)如下所示:

CREATE TABLE #YourTable ([ID] INT, [Name] VARCHAR(MAX), [Value] INT)

INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'Oranges & Lemons',4)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'1 < 2',8)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (2,'C',9)

SELECT  [ID],
  STUFF((
    SELECT ', ' + CAST([Name] AS VARCHAR(MAX))
    FROM #YourTable WHERE (ID = Results.ID) 
    FOR XML PATH(''),TYPE 
     /* Use .value to uncomment XML entities e.g. &gt; &lt; etc*/
    ).value('.','VARCHAR(MAX)') 
  ,1,2,'') as NameValues
FROM    #YourTable Results
GROUP BY ID

DROP TABLE #YourTable

Rather than using a space as a delimiter and replacing all the spaces with commas, it just pre-pends a comma and space to each value then uses STUFFto remove the first two characters.

它不是使用空格作为分隔符并用逗号替换所有空格,而是在每个值前添加一个逗号和空格,然后用于STUFF删除前两个字符。

The XML encoding is taken care of automatically by using the TYPEdirective.

XML 编码是通过使用TYPE指令自动处理的。

回答by cyberkiwi

Another option using Sql Server 2005 and above

使用 Sql Server 2005 及更高版本的另一种选择

---- test data
declare @t table (OUTPUTID int, SCHME varchar(10), DESCR varchar(10))
insert @t select 1125439       ,'CKT','Approved'
insert @t select 1125439       ,'RENO','Approved'
insert @t select 1134691       ,'CKT','Approved'
insert @t select 1134691       ,'RENO','Approved'
insert @t select 1134691       ,'pn','Approved'

---- actual query
;with cte(outputid,combined,rn)
as
(
  select outputid, SCHME + ' ('+DESCR+')', rn=ROW_NUMBER() over (PARTITION by outputid order by schme, descr)
  from @t
)
,cte2(outputid,finalstatus,rn)
as
(
select OUTPUTID, convert(varchar(max),combined), 1 from cte where rn=1
union all
select cte2.outputid, convert(varchar(max),cte2.finalstatus+', '+cte.combined), cte2.rn+1
from cte2
inner join cte on cte.OUTPUTID = cte2.outputid and cte.rn=cte2.rn+1
)
select outputid, MAX(finalstatus) from cte2 group by outputid

回答by Orlando Colamatteo

Install the SQLCLR Aggregates from http://groupconcat.codeplex.com

http://groupconcat.codeplex.com安装 SQLCLR 聚合

Then you can write code like this to get the result you asked for:

然后你可以写这样的代码来得到你要求的结果:

CREATE TABLE foo
(
 id INT,
 name CHAR(1),
 Value CHAR(1)
);

INSERT  INTO dbo.foo
    (id, name, Value)
VALUES  (1, 'A', '4'),
        (1, 'B', '8'),
        (2, 'C', '9');

SELECT  id,
    dbo.GROUP_CONCAT(name + ':' + Value) AS [Column]
FROM    dbo.foo
GROUP BY id;

回答by Shem Sargent

Eight years later... Microsoft SQL Server vNext Database Engine has finally enhanced Transact-SQL to directly support grouped string concatenation. The Community Technical Preview version 1.0 added the STRING_AGG function and CTP 1.1 added the WITHIN GROUP clause for the STRING_AGG function.

八年后... Microsoft SQL Server vNext 数据库引擎终于增强了 Transact-SQL 以直接支持分组字符串连接。Community Technical Preview 1.0 版添加了 STRING_AGG 函数,CTP 1.1 为 STRING_AGG 函数添加了 WITHIN GROUP 子句。

Reference: https://msdn.microsoft.com/en-us/library/mt775028.aspx

参考:https: //msdn.microsoft.com/en-us/library/mt775028.aspx

回答by Joel Coehoorn

SQL Server 2005 and later allow you to create your own custom aggregate functions, including for things like concatenation- see the sample at the bottom of the linked article.

SQL Server 2005 及更高版本允许您创建自己的自定义聚合函数,包括诸如连接之类的事情 - 请参阅链接文章底部的示例。

回答by Phillip

This is just an addition to Kevin Fairchild's post (very clever by the way). I would have added it as a comment, but I don't have enough points yet :)

这只是对 Kevin Fairchild 帖子的补充(顺便说一下,这很聪明)。我会把它添加为评论,但我还没有足够的分数:)

I was using this idea for a view I was working on, however the items I was concatinating contained spaces. So I modified the code slightly to not use spaces as delimiters.

我将这个想法用于我正在处理的视图,但是我连接的项目包含空间。所以我稍微修改了代码,不使用空格作为分隔符。

Again thanks for the cool workaround Kevin!

再次感谢凯文的酷解决方法!

CREATE TABLE #YourTable ( [ID] INT, [Name] CHAR(1), [Value] INT ) 

INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (1, 'A', 4) 
INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (1, 'B', 8) 
INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (2, 'C', 9) 

SELECT [ID], 
       REPLACE(REPLACE(REPLACE(
                          (SELECT [Name] + ':' + CAST([Value] AS VARCHAR(MAX)) as A 
                           FROM   #YourTable 
                           WHERE  ( ID = Results.ID ) 
                           FOR XML PATH (''))
                        , '</A><A>', ', ')
                ,'<A>','')
        ,'</A>','') AS NameValues 
FROM   #YourTable Results 
GROUP  BY ID 

DROP TABLE #YourTable 

回答by Michal B.

An example would be

一个例子是

In Oracle you can use LISTAGG aggregate function.

在 Oracle 中,您可以使用 LISTAGG 聚合函数。

Original records

原始记录

name   type
------------
name1  type1
name2  type2
name2  type3

Sql

数据库

SELECT name, LISTAGG(type, '; ') WITHIN GROUP(ORDER BY name)
FROM table
GROUP BY name

Result in

导致

name   type
------------
name1  type1
name2  type2; type3