考虑一个包含姓名的数据库表格,有三行:
Peter
Paul
Mary
有没有简单的方法将这些内容转换成一个字符串:
Peter, Paul, Mary
?考虑一个包含姓名的数据库表格,有三行:
Peter
Paul
Mary
Peter, Paul, Mary
?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 (''), TYPE
).value('text()[1]','nvarchar(max)') [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 (''), TYPE
).value('text()[1]','nvarchar(max)'), 2, 1000) [Students]
FROM dbo.Students ST2
<
或&
,则此方法无法正常工作。请参见@BenHinman的评论。 - SamFOR XML PATH ('')
行为,这意味着它不应被视为可靠的,因为任何补丁或更新都可能改变其功能方式。基本上,这是依赖于已弃用的功能。 - Bacon Bitsstring_agg
函数,这样一切都可以解决了。 - Jason C使用 COALESCE
:
这个答案可能会返回意外的结果。为了获得一致的结果,请使用其他答案中详细介绍的 FOR XML PATH 方法之一。
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
只是一些解释(因为这个答案似乎经常被查看):
1)不需要使用空字符串值初始化@Names
。
2)不需要在结尾处再次删除额外的分隔符。
@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”替换为适合您的内容])。
从下一个版本的SQL Server开始,我们终于可以跨行连接字符串而不必使用任何变量或XML技巧。
无需分组
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;
SELECT STRING_AGG(CAST(EmpName as NVARCHAR(MAX)), ',')
FROM EmpTable as t
- VarunSTRING_AGG
。这应该是被接受的答案! - Yahya在SQL Server中,还没有展示过通过XML
data()
命令的一种方法是:
假设有一个名为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
SELECT STUFF(REPLACE((SELECT '#!'+city AS 'data()' FROM #cityzip FOR XML PATH ('')),' #!',', '),1,2,'')
- NReilinghSELECT Stuff(
(SELECT N', ' + Name FROM Names FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),1,2,N'')
你可以使用 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字符,这也可以正常工作。
'"},{"_":"'
是安全的,因为如果您的数据包含'"},{"_":"',
它将被转义为"},{\"_\":\"
您可以使用任何字符串分隔符替换', '
您可以使用新的STRING_AGG函数
<
、>
、&
等,而 FOR XML PATH('')
将自动进行转义。 - BateTechSELECT 1 AS a, GROUP_CONCAT(name ORDER BY name ASC SEPARATOR ', ') AS people
FROM users
WHERE id IN (1,2,3)
GROUP BY a
CHAR
类型,您需要进行转换,例如通过GROUP_CONCAT(CAST(id AS CHAR(8)) ORDER BY id ASC SEPARATOR ',')
进行转换;2)如果有许多值传入,您应该根据https://dev59.com/_nM_5IYBdhLWcg3wq1GF#1278210中的说明增加`group_concat_max_len`。 - hardmooth使用 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
PostgreSQL的数组非常棒。例如:
创建一些测试数据:
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版本以来,更容易了。引用“没有名字的马”的删除答案:
select string_agg(name, ',')
from names;
选择array_to_string(array_agg(name ||'('||id||')'
- ProbablePrimeOracle 11g Release 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个字符。
LISTAGG
运行完美!只需阅读此处链接的文档。wm_concat
已从 12c 版本开始删除。 - asgsDECLARE @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
<
或&
时,这会失败。 - Sam