STRING_AGG (Transact-SQL)

适用于:SQL Server 2017 (14.x) 及更高版本Azure SQL 数据库Azure SQL 托管实例Azure Synapse AnalyticsMicrosoft Fabric 中的 SQL 分析终结点Microsoft Fabric 中的仓库

串联字符串表达式的值,并在其间放置分隔符值。 不能在字符串末尾添加分隔符。

Transact-SQL 语法约定

语法

STRING_AGG ( expression, separator ) [ <order_clause> ]

<order_clause> ::=   
    WITHIN GROUP ( ORDER BY <order_by_expression_list> [ ASC | DESC ] )   

注意

若要查看 SQL Server 2014 (12.x) 及更早版本的 Transact-SQL 语法,请参阅早期版本文档

参数

expression
是任何类型的表达式。 串联期间,表达式被转换为 NVARCHARVARCHAR 类型。 非字符串类型被转换为 NVARCHAR 类型。

separator
NVARCHARVARCHAR 类型的表达式,用作串联字符串的分隔符。 可以是文本或变量。

<order_clause>
使用 WITHIN GROUP 子句有选择性地指定串联结果的顺序:

WITHIN GROUP ( ORDER BY <order_by_expression_list> [ ASC | DESC ] )

<order_by_expression_list>

可用于对结果进行排序的一系列非常量表达式。 每个查询只允许使用一个 order_by_expression。 默认的排序顺序为升序。

返回类型

返回类型取决于第一个参数(表达式)。 如果输入参数是字符串类型(NVARCHARVARCHAR,则结果类型与输入类型相同。 下表列出了自动转换:

输入表达式类型 结果
NVARCHAR(MAX) NVARCHAR(MAX)
VARCHAR(MAX) VARCHAR(MAX)
NVARCHAR(1...4000) NVARCHAR(4000)
VARCHAR(1...8000) VARCHAR(8000)
int, bigint, smallint, tinyint, numeric, float, real, bit, decimal, smallmoney, money, datetime, datetime2, NVARCHAR(4000)

注解

STRING_AGG 是一个聚合函数,用于提取行中的所有表达式,并将这些表达式串联成一个字符串。 表达式值隐式转换为字符串类型,然后串联在一起。 隐式转换为字符串的过程遵循现有的数据类型转换规则。 有关数据类型转换的详细信息,请参阅 CAST 和 CONVERT (Transact-SQL)

如果输入表达式的类型为 VARCHAR,则分隔符的类型不能是 NVARCHAR

null 值会被忽略,且不会添加相应的分隔符。 若要为 null 值返回占位符,请使用 ISNULL 函数,如示例 B 中所示。

STRING_AGG 适用于任何兼容级别。

注意

<order_clause> 适用于数据库兼容性级别 110 及更高级别。

示例

本文中的大多数示例都引用 AdventureWorks 示例数据库

A. 生成以新行分隔的姓名列表

下面的示例在一个结果单元格中生成姓名列表,并将其以回车符分隔。

USE AdventureWorks2022;
GO
SELECT STRING_AGG (CONVERT(NVARCHAR(max),FirstName), CHAR(13)) AS csv 
FROM Person.Person;
GO

下面是结果集。

csv
Syed
Catherine
Kim
Kim
Kim
Hazem
...

结果中未返回 name 单元格中的 NULL 值。

注意

如果使用 SQL Server Management Studio 查询编辑器,“结果显示为网格”选项无法实现回车符。 可切换到“结果显示为文本”,以便正确查看结果集
默认情况下,“结果显示为文本”截断为 256 个字符。 若要增加此限制,请更改“每个列中显示的最大字符数”选项。

B. 生成使用逗号分隔且不带 NULL 值的姓名列表

下面的示例在一个结果单元格中返回以逗号分隔的姓名,并使用“N/A”替换 null 值。

USE AdventureWorks2022;
GO
SELECT STRING_AGG(CONVERT(NVARCHAR(max), ISNULL(FirstName,'N/A')), ',') AS csv 
FROM Person.Person;
GO

下面是结果集。

注意

将显示剪裁后的结果。

csv
Syed,Catherine,Kim,Kim,Kim,Hazem,Sam,Humberto,Gustavo,Pilar,Pilar, ...

C. 生成采用逗号分隔的值

USE AdventureWorks2022;
GO
SELECT STRING_AGG(CONVERT(NVARCHAR(max), CONCAT(FirstName, ' ', LastName, '(', ModifiedDate, ')')), CHAR(13)) AS names 
FROM Person.Person;
GO

下面是结果集。

注意

将显示剪裁后的结果。

姓名
Ken Sánchez (Feb 8 2003 12:00AM)
Terri Duffy (Feb 24 2002 12:00AM)
Roberto Tamburello (Dec 5 2001 12:00AM)
Rob Walters (Dec 29 2001 12:00AM)
...

注意

如果使用 Management Studio 查询编辑器,“结果显示为网格”选项无法实现回车符。 可切换到“结果显示为文本”,以便正确查看结果集

假设有一个数据库,其中的文章及其标记都被分隔到了不同的表中。 开发人员想在返回时将每篇文章及其所有关联标记作为一行。 以下查询实现了此结果:

SELECT a.articleId, title, STRING_AGG (tag, ',') as tags
FROM dbo.Article AS a
LEFT JOIN dbo.ArticleTag AS t
    ON a.ArticleId = t.ArticleId
GROUP BY a.articleId, title;
GO

下面是结果集。

articleId title 标记
172 参选方民调结果不相上下 政治,民意调查,市参议会
176 新高速公路有望减少交通拥塞 Null
177 狗继续比猫更受人喜爱 民意调查,动物

注意

如果 STRING_AGG 函数不是 SELECT 列表中的唯一项,则需要子句 GROUP BY

E. 生成按城市分类的电子邮件列表

下面的查询用于查找员工的电子邮件地址,并将结果按城市分类:

USE AdventureWorks2022;
GO

SELECT TOP 10 City, STRING_AGG(CONVERT(NVARCHAR(max), EmailAddress), ';') AS emails 
FROM Person.BusinessEntityAddress AS BEA  
INNER JOIN Person.Address AS A ON BEA.AddressID = A.AddressID
INNER JOIN Person.EmailAddress AS EA ON BEA.BusinessEntityID = EA.BusinessEntityID 
GROUP BY City;
GO

下面是结果集。

注意

将显示剪裁后的结果。

City emails
Ballard paige28@adventure-works.com;joshua24@adventure-works.com;javier12@adventure-works.com;...
Baltimore gilbert9@adventure-works.com
Barstow kristen4@adventure-works.com
Basingstoke Hants dale10@adventure-works.com;heidi9@adventure-works.com
Baytown kelvin15@adventure-works.com
Beaverton billy6@adventure-works.com;dalton35@adventure-works.com;lawrence1@adventure-works.com;...
Bell Gardens christy8@adventure-works.com
Bellevue min0@adventure-works.com;gigi0@adventure-works.com;terry18@adventure-works.com;...
Bellflower philip0@adventure-works.com;emma34@adventure-works.com;jorge8@adventure-works.com;...
Bellingham christopher23@adventure-works.com;frederick7@adventure-works.com;omar0@adventure-works.com;...

可以直接使用在电子邮件列中返回的电子邮件向在某些特定城市工作的人们发送电子邮件。

F. 生成按城市分类并经过排序的电子邮件列表

与上一个示例类似,下面的查询将查找员工的电子邮件地址,将结果按城市分类,并按字母顺序对电子邮件排序:

USE AdventureWorks2022;
GO

SELECT TOP 10 City, STRING_AGG(CONVERT(NVARCHAR(max), EmailAddress), ';') WITHIN GROUP (ORDER BY EmailAddress ASC) AS Emails 
FROM Person.BusinessEntityAddress AS BEA  
INNER JOIN Person.Address AS A ON BEA.AddressID = A.AddressID
INNER JOIN Person.EmailAddress AS EA ON BEA.BusinessEntityID = EA.BusinessEntityID 
GROUP BY City;
GO

下面是结果集。

注意

将显示剪裁后的结果。

City 电子邮件
Barstow kristen4@adventure-works.com
Basingstoke Hants dale10@adventure-works.com;heidi9@adventure-works.com
Braintree mindy20@adventure-works.com
Bell Gardens christy8@adventure-works.com
Byron louis37@adventure-works.com
Bordeaux ranjit0@adventure-works.com
Carnation don0@adventure-works.com;douglas0@adventure-works.com;george0@adventure-works.com;...
Boulogne-Billancourt allen12@adventure-works.com;bethany15@adventure-works.com;carl5@adventure-works.com;...
Berkshire barbara41@adventure-works.com;brenda4@adventure-works.com;carrie14@adventure-works.com;...
Berks adriana6@adventure-works.com;alisha13@adventure-works.com;arthur19@adventure-works.com;...

后续步骤

在以下文章中了解有关 Transact-SQL 函数的详细信息: