STRING_AGG (Transact-SQL)

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

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

Transact-SQL 语法约定

语法

STRING_AGG ( expression , separator ) [ <order_clause> ]

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

参数

expression

任何类型的 表达式。 表达式在串联期间转换为 nvarchar varchar 类型。 非字符串类型转换为 nvarchar 类型。

separator

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

<order_clause>

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

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

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

返回类型

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

输入表达式类型 结果
nvarchar(max) nvarchar(max)
varchar(max) varchar(max)
nvarchar(1..4000) nvarchar(4000)
varchar(1..8000) varchar(8000)
intbigintsmallinttinyint数值浮点实际
十进制smallmoney货币日期时间datetime2
nvarchar(4000)

注解

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

如果输入表达式的类型 varchar,则分隔符不能 nvarchar类型。

忽略 Null 值,并且不会添加相应的分隔符。 若要返回空值的位置持有者,请使用 ISNULL 函数,如 示例 B所示。

STRING_AGG 适用于任何兼容级别。

注意

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

示例

本文中的 Transact-SQL 代码示例使用 AdventureWorks2022AdventureWorksDW2022 示例数据库,可以从 Microsoft SQL Server 示例和社区项目 主页下载该数据库。

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
...

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

注意

如果使用 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

下面是剪裁的结果集。

names
-------
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 OUTER JOIN dbo.ArticleTag AS t
         ON a.ArticleId = t.ArticleId
GROUP BY a.articleId, title;
GO

结果集如下。

articleId title 标记
172 Polls indicate close election results politics,polls,city council
176 New highway expected to reduce congestion NULL
177 Dogs continue to be more popular than cats polls,animals

注意

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

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...