如何在SQL Server中将多行文本合并为单个文本字符串?


1910

考虑一个包含名称的数据库表,该表具有三行:

Peter
Paul
Mary

有没有简单的方法可以将其转换为单个字符串Peter, Paul, Mary


26
对于特定于SQL Server的答案,请尝试此问题
马特·汉密尔顿,

17
对于MySQL,请从此答案中查看Group_Concat
Pykler,2011年

26
我希望SQL Server的下一版本将提供一个新功能,以优雅地解决多行字符串混淆问题,而又不会使FOR XML PATH变得愚蠢。
皮特·阿尔文

4
不是SQL,但是如果这只是一次操作,则可以将列表粘贴到此浏览器内工具convert.town/column-to-comma-separated-list
Stack Man

3
在Oracle中,您可以使用11g r2中的LISTAGG(COLUMN_NAME),然后再执行不支持的称为WM_CONCAT(COLUMN_NAME)的功能。
理查德

Answers:


1431

如果您使用的是SQL Server 2017或Azure,请参阅Mathieu Renda的答案

当我试图以一对多关系联接两个表时,我遇到了类似的问题。在SQL 2005中,我发现该XML PATH方法可以非常轻松地处理行的串联。

如果有一个名为 STUDENTS

SubjectID       StudentName
----------      -------------
1               Mary
1               John
1               Sam
2               Alaina
2               Edward

我预期的结果是:

SubjectID       StudentName
----------      -------------
1               Mary, John, Sam
2               Alaina, Edward

我使用以下内容T-SQL

SELECT Main.SubjectID,
       LEFT(Main.Students,Len(Main.Students)-1) As "Students"
FROM
    (
        SELECT DISTINCT ST2.SubjectID, 
            (
                SELECT ST1.StudentName + ',' AS [text()]
                FROM dbo.Students ST1
                WHERE ST1.SubjectID = ST2.SubjectID
                ORDER BY ST1.SubjectID
                FOR XML PATH ('')
            ) [Students]
        FROM dbo.Students ST2
    ) [Main]

如果可以在开头合并逗号并用于substring跳过第一个逗号,则可以以更紧凑的方式执行相同的操作,因此无需执行子查询:

SELECT DISTINCT ST2.SubjectID, 
    SUBSTRING(
        (
            SELECT ','+ST1.StudentName  AS [text()]
            FROM dbo.Students ST1
            WHERE ST1.SubjectID = ST2.SubjectID
            ORDER BY ST1.SubjectID
            FOR XML PATH ('')
        ), 2, 1000) [Students]
FROM dbo.Students ST2

13
很好的解决方案。如果您需要处理HTML中的特殊字符,以下内容可能会有所帮助:Rob Farley:使用FOR XML PATH('')处理特殊字符

10
显然,如果名称包含XML字符(例如<或),则此方法将无效&。参见@BenHinman的评论。
山姆

23
注意:此方法取决于的未记录行为FOR XML PATH ('')。这意味着不应将其视为可靠的,因为任何补丁程序或更新都可能改变其功能。它基本上依赖于已弃用的功能。
培根

26
@Whelkaholism底线是FOR XML用来生成XML,而不是连接任意字符串。这就是为什么它逃脱 &<>以XML实体代码(&amp;&lt;&gt;)。我相信它也将逃脱",并'&quot;&apos;在属性为好。它不是 GROUP_CONCAT()string_agg()array_agg()listagg(),等。即使你可以种做它做到这一点。我们应该花时间要求Microsoft实现适当的功能。
培根钻头

13
好消息:v.Next 中将添加MS SQL Server string_agg所有这些都可以消失。
Jason C

1008

该答案可能会返回意外结果。为获得一致的结果,请使用其他答案中详细介绍的FOR XML PATH方法之一。

用途COALESCE

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + Name 
FROM People

只是一些解释(因为此答案似乎获得了相对常规的意见):

  • 实际上,Coalcece只是一个有用的作弊手段,可以完成两件事:

1)无需@Names使用空字符串值进行初始化。

2)无需在末端剥离额外的分隔器。

  • 如果行具有NULL名称值,则上述解决方案将给出错误的结果(如果存在NULL,则NULL将在该行之后使@Names NULL,并且下一行将再次作为空字符串重新开始。很容易用两个中的一个来修复解决方案:
DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
WHERE Name IS NOT NULL

要么:

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + 
    ISNULL(Name, 'N/A')
FROM People

根据您想要的行为而定(第一个选项仅过滤掉NULL,第二个选项通过标记消息将它们保留在列表中[将'N / A'替换为适合您的内容))。


72
需要明确的是,合并与创建列表无关,它只是确保不包括NULL值。
Graeme Perrow,2009年

17
@Graeme Perrow它不排除NULL值(为此需要一个WHERE -如果输入值之一为NULL,它将丢失结果),并且在这种方法中是必需的,因为:NULL +非NULL-> NULL和非NULL + NULL-> NULL; @Name默认情况下也为NULL,实际上,该属性在此处用作隐式前哨,以确定是否应添加','。

62
请注意,这种串联方法取决于SQL Server使用特定计划执行查询。使用此方法(添加了ORDER BY)使我陷入困境。当它处理少量的行时,它可以正常工作,但具有更多的数据,SQL Server选择了不同的计划,这导致选择没有任何连接的第一项。请参见本文由Anith参议员
fbarber

17
此方法不能用作选择列表或where子句中的子查询,因为它使用tSQL变量。在这种情况下,您可以使用@Ritesh
R. Schreurs

11
这不是可靠的连接方法。它不受支持并且不应使用(对于Microsoft,例如,support.microsoft.com / en-us / kb / 287515connect.microsoft.com/SQLServer/Feedback/Details/704389)。它可以更改而不会发出警告。使用中讨论的XML路径技术stackoverflow.com/questions/5031204/...我写的更多在这里:marc.durdin.net/2015/07/...
马克Durdin

452

SQL Server 2017+和SQL Azure:STRING_AGG

从下一个版本的SQL Server开始,我们最终可以跨行连接,而不必诉诸任何变量或XML问题。

STRING_AGG(Transact-SQL)

不分组

SELECT STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department;

与分组:

SELECT GroupName, STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department
GROUP BY GroupName;

带分组和子分类

SELECT GroupName, STRING_AGG(Name, ', ') WITHIN GROUP (ORDER BY Name ASC) AS Departments
FROM HumanResources.Department 
GROUP BY GroupName;

2
而且,与CLR解决方案不同,您可以控制排序。
佳能

STRING_AGG似乎有4000个字符的显示限制
InspiredBy

如果没有GROUP BY,是否可以进行排序(对于“无分组”示例)?
RuudvK

更新:我设法执行以下操作,但是有没有一种更清洁的方法?SELECT STRING_AGG(Name,',')AS Departments FROM(SELECT TOP 100000 Name from HumanResources.Department ORDER BY Name)D;
RuudvK

362

XML data()MS SQL Server中尚未通过命令显示的一种方法是:

假设表名为NameList,其中一列称为FName,

SELECT FName + ', ' AS 'data()' 
FROM NameList 
FOR XML PATH('')

返回:

"Peter, Paul, Mary, "

只有多余的逗号必须被处理。

编辑:从@NReilingh的评论中采用,您可以使用以下方法删除结尾的逗号。假设表和列名称相同:

STUFF(REPLACE((SELECT '#!' + LTRIM(RTRIM(FName)) AS 'data()' FROM NameList
FOR XML PATH('')),' #!',', '), 1, 2, '') as Brands

15
真是太神奇了!单独执行时(如您的示例中所示),结果格式为超链接,单击(在SSMS中)会打开一个包含数据的新窗口,但是当用作较大查询的一部分时,它只是显示为字符串。是字符串吗?还是我将在使用此数据的应用程序中需要区别对待的xml?
2012年

10
这种方法还可以对XML进行转义,例如<和>。所以,如果选择'的<b>' + FName参数+ '</ B>'在结果中“保...&LT b取代;约翰&LT; / B&GT;&LT; b取代”
卢卡斯兰斯基

8
干净的解决方案。我注意到即使不添加,+ ', '它仍会在每个串联的元素之间添加一个空格。
鲍达德2014年

8
@Baodad这似乎是交易的一部分。您可以通过替换添加的令牌字符来解决。例如,这可以为任何长度的列表提供一个完美的逗号分隔列表:SELECT STUFF(REPLACE((SELECT '#!'+city AS 'data()' FROM #cityzip FOR XML PATH ('')),' #!',', '),1,2,'')
NReilingh

1
哇,实际上在我使用data()和replace的测试中,性能要比没有好。超级奇怪
NReilingh '16

306

SQL Server 2005中

SELECT Stuff(
  (SELECT N', ' + Name FROM Names FOR XML PATH(''),TYPE)
  .value('text()[1]','nvarchar(max)'),1,2,N'')

在SQL Server 2016中

您可以使用FOR JSON语法

SELECT per.ID,
Emails = JSON_VALUE(
   REPLACE(
     (SELECT _ = em.Email FROM Email em WHERE em.Person = per.ID FOR JSON PATH)
    ,'"},{"_":"',', '),'$[0]._'
) 
FROM Person per

结果将成为

Id  Emails
1   abc@gmail.com
2   NULL
3   def@gmail.com, xyz@gmail.com

即使您的数据包含无效的XML字符,这也将起作用

'"},{"_":"'是安全的,因为如果您包含的数据'"},{"_":"',将被转义到"},{\"_\":\"

您可以', '用任何字符串分隔符替换


在SQL Server 2017中,Azure SQL数据库

您可以使用新的STRING_AGG函数


3
很好地利用STUFF函数来消除前两个字符。
大卫,

3
我最喜欢此解决方案,因为我可以通过将'as <label>'附加在选择列表中轻松使用它。我不确定如何使用@Ritesh的解决方案来执行此操作。
R. Schreurs

13
这比接受的答案更好,因为该选项还可以处理非XML转义字符,被保留的,如<>&,等它FOR XML PATH('')会自动逃跑。
BateTech

这是一个很棒的响应,因为它解决了该问题,并提供了在不同版本的SQL中执行操作的最佳方法,现在我希望我可以使用2017 / Azure
Chris Ward,

120

在MySQL中,有一个函数GROUP_CONCAT(),它允许您将多行中的值连接起来。例:

SELECT 1 AS a, GROUP_CONCAT(name ORDER BY name ASC SEPARATOR ', ') AS people 
FROM users 
WHERE id IN (1,2,3) 
GROUP BY a

效果很好。但是当我使用时,SEPARATOR '", "'我会在最后一个条目的末尾错过一些字符。为什么会发生这种情况?
gooleem '16

@gooleem我不清楚您的意思,但是此功能仅将分隔符放在项目之间,而不是后面。如果那不是答案,我建议您发布一个新问题。
达里尔·海因

@DarrylHein为我的需要,我如上所述使用分隔符。但这在输出的最后削减了我一些字符。这很奇怪,似乎是一个错误。我没有解决方案,我只是解决方法。
gooleem '16

基本工作。两件事情来考虑:1)如果你的列不是CHAR,你需要将其强制转换,例如,通过GROUP_CONCAT( CAST(id AS CHAR(8)) ORDER BY id ASC SEPARATOR ',')2)如果你有很多价值观的到来,则应该增加group_concat_max_len写在stackoverflow.com/a/1278210/1498405
hardmooth

58

使用COALESCE - 了解更多来自这里

例如:

102

103

104

然后在sql server中编写以下代码,

Declare @Numbers AS Nvarchar(MAX) -- It must not be MAX if you have few numbers 
SELECT  @Numbers = COALESCE(@Numbers + ',', '') + Number
FROM   TableName where Number IS NOT NULL

SELECT @Numbers

输出为:

102,103,104

2
这确实是IMO的最佳解决方案,因为它避免了FOR XML提出的编码问题。我用过Declare @Numbers AS Nvarchar(MAX),效果很好。您能否解释为什么建议不使用它?
EvilDr

7
该解决方案已经在8年前发布了!stackoverflow.com/a/194887/986862
Andre Figueiredo'5

为什么此查询返回??? 符号而不是西里尔字母?这只是输出问题吗?
Akmal Salikhov

48

Postgres数组很棒。例:

创建一些测试数据:

postgres=# \c test
You are now connected to database "test" as user "hgimenez".
test=# create table names (name text);
CREATE TABLE                                      
test=# insert into names (name) values ('Peter'), ('Paul'), ('Mary');                                                          
INSERT 0 3
test=# select * from names;
 name  
-------
 Peter
 Paul
 Mary
(3 rows)

将它们聚合成一个数组:

test=# select array_agg(name) from names;
 array_agg     
------------------- 
 {Peter,Paul,Mary}
(1 row)

将数组转换为逗号分隔的字符串:

test=# select array_to_string(array_agg(name), ', ') from names;
 array_to_string
-------------------
 Peter, Paul, Mary
(1 row)

完成

从PostgreSQL 9.0开始,它变得更加容易


如果您需要多个列,例如括号中的员工编号,请使用concat运算符: select array_to_string(array_agg(name||'('||id||')'
理查德·福克斯

不适用于sql-server,仅适用于mysql
GoldBishop

46

Oracle 11g第2版支持LISTAGG功能。文档在这里

COLUMN employees FORMAT A50

SELECT deptno, LISTAGG(ename, ',') WITHIN GROUP (ORDER BY ename) AS employees
FROM   emp
GROUP BY deptno;

    DEPTNO EMPLOYEES
---------- --------------------------------------------------
        10 CLARK,KING,MILLER
        20 ADAMS,FORD,JONES,SCOTT,SMITH
        30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD

3 rows selected.

警告

如果结果字符串可能超过4000个字符,请小心实现此功能。它将引发异常。在这种情况下,您需要处理异常或滚动自己的函数,以防止连接的字符串超过4000个字符。


1
对于旧版本的Oracle,wm_concat是完美的。Alex的链接礼物中解释了其用法。谢谢亚历克斯!
toscanelli

LISTAGG完美的作品!只需阅读此处链接的文档。wm_concat从版本12c开始删除。
ass

34

在SQL Server 2005及更高版本中,使用下面的查询来连接行。

DECLARE @t table
(
    Id int,
    Name varchar(10)
)
INSERT INTO @t
SELECT 1,'a' UNION ALL
SELECT 1,'b' UNION ALL
SELECT 2,'c' UNION ALL
SELECT 2,'d' 

SELECT ID,
stuff(
(
    SELECT ','+ [Name] FROM @t WHERE Id = t.Id FOR XML PATH('')
),1,1,'') 
FROM (SELECT DISTINCT ID FROM @t ) t

2
我相信当值包含XML符号(例如<或)时,此操作将失败&
山姆

28

我没有在家中使用SQL Server的权限,所以我猜这里的语法,但它或多或少:

DECLARE @names VARCHAR(500)

SELECT @names = @names + ' ' + Name
FROM Names

11
您需要将@name初始化为非空值,否则整个过程都将为NULL。您还需要处理定界符(包括不必要的定界符)
Marc Gravell

3
这种方法(我一直使用)唯一的问题是您无法嵌入它
ekkis 2012年

1
要摆脱领先空间,请将查询更改为SELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ' ' END + Name FROM Names
Tian van Heerden

另外,您必须检查Name是否不为空,您可以通过以下方式进行操作:SELECT @names = @names + ISNULL(' ' + Name, '')
Vita1ij

28

建议使用递归CTE解决方案,但未提供任何代码。下面的代码是递归CTE的示例。请注意,尽管结果符合问题,但数据与给定的说明并不完全一样,因为我假设您确实想对行组(而不是表中的所有行)执行此操作。读者可以将其更改为与表中的所有行匹配以作为练习。

;WITH basetable AS (
    SELECT
        id,
        CAST(name AS VARCHAR(MAX)) name, 
        ROW_NUMBER() OVER (Partition BY id ORDER BY seq) rw, 
        COUNT(*) OVER (Partition BY id) recs 
    FROM (VALUES
        (1, 'Johnny', 1),
        (1, 'M', 2), 
        (2, 'Bill', 1),
        (2, 'S.', 4),
        (2, 'Preston', 5),
        (2, 'Esq.', 6),
        (3, 'Ted', 1),
        (3, 'Theodore', 2),
        (3, 'Logan', 3),
        (4, 'Peter', 1),
        (4, 'Paul', 2),
        (4, 'Mary', 3)
    ) g (id, name, seq)
),
rCTE AS (
    SELECT recs, id, name, rw
    FROM basetable
    WHERE rw = 1

    UNION ALL

    SELECT b.recs, r.ID, r.name +', '+ b.name name, r.rw + 1
    FROM basetable b
    INNER JOIN rCTE r ON b.id = r.id AND b.rw = r.rw + 1
)
SELECT name
FROM rCTE
WHERE recs = rw AND ID=4

1
对于大吃一惊:此查询插入物12点的行(3列)到一个临时basetable,然后创建一个递归公用表表达式(rCTE),然后变平的name 柱到4个以逗号分隔的字符串id第 乍一看,我认为这比大多数其他SQL Server解决方案要完成的工作更多。
knb

2
@knb:不确定是赞美,定罪还是惊讶。基表是因为我喜欢我的示例可以实际工作,所以它实际上与问题没有任何关系。
jmoreno '17

26

您需要创建一个变量来保存最终结果,然后选择它,就像这样。

最简单的解决方案

DECLARE @char VARCHAR(MAX);

SELECT @char = COALESCE(@char + ', ' + [column], [column]) 
FROM [table];

PRINT @char;

25

从PostgreSQL 9.0开始,这非常简单:

select string_agg(name, ',') 
from names;

在9.0之前的版本array_agg()中可以使用,如hgmnz所示


要对非文本类型的列执行此操作,您需要添加类型转换:SELECT string_agg(non_text_type::text, ',') FROM table
Torben Kohlmeier

@TorbenKohlmeier:您只需要非字符列(例如,整数,十进制)。它可以正常工作,varchar或者char
a_horse_with_no_name13年


18

使用XML有助于我用逗号分隔行。对于多余的逗号,我们可以使用SQL Server的替换功能。不用添加逗号,而是使用AS'data()'将行与空格连接起来,以后可以用逗号替换,如下所示。

REPLACE(
        (select FName AS 'data()'  from NameList  for xml path(''))
         , ' ', ', ') 

2
这是我认为最好的答案。当需要连接到另一个表时,使用声明变量是不好的,这很不错而且很简短。辛苦了
David Roussel

7
如果FName数据已经有空格,例如“我的名字”
binball 2011年

在MS-SQL 2016上确实对我有用,')as allBrands
Rejwanul Reja

17

一个现成的解决方案,无需多余的逗号:

select substring(
        (select ', '+Name AS 'data()' from Names for xml path(''))
       ,3, 255) as "MyList"

空列表将导致NULL值。通常,您会将列表插入表格列或程序变量中:根据需要调整255最大长度。

(Diwakar和Jens Frandsen提供了很好的答案,但需要改进。)


使用此命令时,逗号前有一个空格:(
slayernoah

1
如果您不需要多余的空间,请替换', '','
Daniel Reis

13
SELECT STUFF((SELECT ', ' + name FROM [table] FOR XML PATH('')), 1, 2, '')

这是一个示例:

DECLARE @t TABLE (name VARCHAR(10))
INSERT INTO @t VALUES ('Peter'), ('Paul'), ('Mary')
SELECT STUFF((SELECT ', ' + name FROM @t FOR XML PATH('')), 1, 2, '')
--Peter, Paul, Mary

10
DECLARE @Names VARCHAR(8000)
SELECT @name = ''
SELECT @Names = @Names + ',' + Names FROM People
SELECT SUBSTRING(2, @Names, 7998)

这将逗号开头。

但是,如果您需要其他列,或者要用CSV子表的形式,则需要将其包装在标量用户定义字段(UDF)中。

您也可以在SELECT子句中将XML路径用作相关子查询(但我必须等到我重新上班,因为Google在家不做任何工作:-)


10

对于其他答案,阅读答案的人必须知道特定的域表,例如车辆或学生。必须创建该表并在其中填充数据以测试解决方案。

下面是使用SQL Server“ Information_Schema.Columns”表的示例。通过使用此解决方案,无需创建表或添加数据。本示例为数据库中的所有表创建一个用逗号分隔的列名列表。

SELECT
    Table_Name
    ,STUFF((
        SELECT ',' + Column_Name
        FROM INFORMATION_SCHEMA.Columns Columns
        WHERE Tables.Table_Name = Columns.Table_Name
        ORDER BY Column_Name
        FOR XML PATH ('')), 1, 1, ''
    )Columns
FROM INFORMATION_SCHEMA.Columns Tables
GROUP BY TABLE_NAME 

7

对于Oracle DB,请参见以下问题:如何在不创建存储过程的情况下将多行连接到Oracle中?

最好的答案似乎是@Emmanuel,它使用Oracle 11g第2版及更高版本中提供的内置LISTAGG()函数。

SELECT question_id,
   LISTAGG(element_id, ',') WITHIN GROUP (ORDER BY element_id)
FROM YOUR_TABLE;
GROUP BY question_id

正如@ user762952指出的那样,根据Oracle文档http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php,WM_CONCAT()函数也是一个选择。它似乎很稳定,但是Oracle明确建议不要在任何应用程序SQL中使用它,因此,使用后果自负。

除此之外,您将不得不编写自己的函数;上面的Oracle文档提供了有关如何执行此操作的指南。


7

为了避免空值,可以使用CONCAT()

DECLARE @names VARCHAR(500)
SELECT @names = CONCAT(@names, ' ', name) 
FROM Names
select @names

很高兴知道CONCAT 为什么起作用。到MSDN的链接会很好。
逆向工程师

7

我真的很喜欢Dana的回答的优美。只是想使其完整。

DECLARE @names VARCHAR(MAX)
SET @names = ''

SELECT @names = @names + ', ' + Name FROM Names 

-- Deleting last two symbols (', ')
SET @sSql = LEFT(@sSql, LEN(@sSql) - 1)

如果要删除最后两个符号',',则需要在名称后添加','('SELECT \ @names = \ @names + Name +','FROM Names')。这样,最后两个字符将始终为','。
JT_

在我的情况下,我需要除去前导逗号,因此将查询更改为,SELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ', ' END + Name FROM Names然后您就不必随后截断它了。
蒂安·范·海登

6

这个答案将需要服务器中的一些特权才能工作。

装配对您来说是个不错的选择。有很多网站介绍了如何创建它。我认为很好地解释了这一点

如果需要,我已经创建了程序集,可以在此处下载DLL 。

下载后,您将需要在SQL Server中运行以下脚本:

CREATE Assembly concat_assembly 
   AUTHORIZATION dbo 
   FROM '<PATH TO Concat.dll IN SERVER>' 
   WITH PERMISSION_SET = SAFE; 
GO 

CREATE AGGREGATE dbo.concat ( 

    @Value NVARCHAR(MAX) 
  , @Delimiter NVARCHAR(4000) 

) RETURNS NVARCHAR(MAX) 
EXTERNAL Name concat_assembly.[Concat.Concat]; 
GO  

sp_configure 'clr enabled', 1;
RECONFIGURE

请注意,服务器可能可以访问组装路径。由于您已成功完成所有步骤,因此可以使用以下功能:

SELECT dbo.Concat(field1, ',')
FROM Table1

希望能帮助到你!!!


1
DLL链接是404错误。为此使用组件是过大的。查看SQL Server的最佳答案
邻近

6

MySQL完整示例:

我们有可以拥有许多数据的用户,并且我们希望有一个输出,我们可以在列表中查看所有用户数据:

结果:

___________________________
| id   |  rowList         |
|-------------------------|
| 0    | 6, 9             |
| 1    | 1,2,3,4,5,7,8,1  |
|_________________________|

表格设定:

CREATE TABLE `Data` (
  `id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1;


INSERT INTO `Data` (`id`, `user_id`) VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1),
(6, 0),
(7, 1),
(8, 1),
(9, 0),
(10, 1);


CREATE TABLE `User` (
  `id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


INSERT INTO `User` (`id`) VALUES
(0),
(1);

查询:

SELECT User.id, GROUP_CONCAT(Data.id ORDER BY Data.id) AS rowList FROM User LEFT JOIN Data ON User.id = Data.user_id GROUP BY User.id

5

我通常使用这样的select来连接SQL Server中的字符串:

with lines as 
( 
  select 
    row_number() over(order by id) id, -- id is a line id
    line -- line of text.
  from
    source -- line source
), 
result_lines as 
( 
  select 
    id, 
    cast(line as nvarchar(max)) line 
  from 
    lines 
  where 
    id = 1 
  union all 
  select 
    l.id, 
    cast(r.line + N', ' + l.line as nvarchar(max))
  from 
    lines l 
    inner join 
    result_lines r 
    on 
      l.id = r.id + 1 
) 
select top 1 
  line
from
  result_lines
order by
  id desc

5

如果要处理空值,可以通过添加where子句或在第一个子句周围添加另一个COALESCE来实现。

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(COALESCE(@Names + ', ', '') + Name, @Names) FROM People

5

这对我有用SqlServer 2016):

SELECT CarNamesString = STUFF((
         SELECT ',' + [Name]
            FROM tbl_cars 
            FOR XML PATH('')
         ), 1, 1, '')

这是来源:https : //www.mytecbits.com/

MySql的解决方案(因为此页面在Google for MySql中显示)

SELECT [Name],
       GROUP_CONCAT(DISTINCT [Name]  SEPARATOR ',')
       FROM tbl_cars

MySql文档



4

这也可能有用

create table #test (id int,name varchar(10))
--use separate inserts on older versions of SQL Server
insert into #test values (1,'Peter'), (1,'Paul'), (1,'Mary'), (2,'Alex'), (3,'Jack')

DECLARE @t VARCHAR(255)
SELECT @t = ISNULL(@t + ',' + name, name) FROM #test WHERE id = 1
select @t
drop table #test

退货

Peter,Paul,Mary

5
不幸的是,这种行为似乎并未得到正式支持。MSDN说:“如果在选择列表中引用了变量,则应为它分配标量值,否则SELECT语句应仅返回一行。” 有人观察到了问题:sqlmag.com/sql-server/multi-row-variable-assignment-and-order
2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.