STRING_AGG (Transact-SQL)

Applies to: SQL Server 2017 (14.x) and later Azure SQL DatabaseAzure SQL Managed InstanceAzure Synapse AnalyticsSQL analytics endpoint in Microsoft FabricWarehouse in Microsoft Fabric

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

Transact-SQL 语法约定

Syntax

STRING_AGG ( expression , separator ) [ <order_clause> ]

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

Arguments

expression

An expression of any type. Expressions are converted to nvarchar or varchar types during concatenation. Non-string types are converted to nvarchar type.

separator

An expression of nvarchar or varchar type that is used as separator for concatenated strings. 可以是文本或变量。

<order_clause>

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

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

    A list of non-constant expressions that can be used for sorting results. 每个查询只允许使用一个 <order_by_expression_list>。 默认的排序顺序为升序。

Return types

返回类型取决于第一个参数(表达式)。 If input argument is string type (nvarchar, varchar), the result type is the same as the input type. 下表列出了自动转换:

输入表达式类型 Result
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)

Remarks

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

If the input expression is type varchar, the separator can't be type nvarchar.

忽略 Null 值,并且不会添加相应的分隔符。 To return a place holder for null values, use the ISNULL function as demonstrated in example B.

STRING_AGG 适用于任何兼容级别。

Note

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

Examples

本文中的代码示例使用 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 值。

Note

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

B. 生成用逗号分隔的中间名称列表,不带 NULL 值

以下示例使用值替换 NULLN/A ,并返回单个结果单元格中用逗号分隔的名称。

USE AdventureWorks2022;
GO

SELECT STRING_AGG(CONVERT (NVARCHAR (MAX), ISNULL(MiddleName, 'N/A')), ',') AS csv
FROM Person.Person;
GO

下面是剪裁的结果集。

csv
-----
E,R.,N/A,N/A,B,E,N/A,N/A,N/A,N/A,G,B,N/A,C,J,L,P,N/A,M,N/A,N/A,N/A,L,J., ...

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

Note

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

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

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

Note

如果 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 Emails
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...