Mas*_* Yi 9 sql sql-server string-aggregation
任何人都可以帮助我使这个查询适用于sql server 2014.这是在Postgresql和可能在sql server 2017上工作.在Oracle上它是listagg而不是string_agg.
这是sql:
select
string_agg(t.id,',') AS id
from Tabel t
Run Code Online (Sandbox Code Playgroud)
我在网站上检查了一些xml选项应该使用但我无法理解.
use*_*983 23
请注意,对于某些字符,使用 时,值将被转义FOR XML PATH
,例如:
SELECT STUFF((SELECT ',' + V.String
FROM (VALUES('7 > 5'),('Salt & pepper'),('2
lines'))V(String)
FOR XML PATH('')),1,1,'');
Run Code Online (Sandbox Code Playgroud)
这将返回以下字符串:
7 > 5,Salt & pepper,2
lines'
Run Code Online (Sandbox Code Playgroud)
这不太可能是我们所希望的。您可以使用TYPE
然后获取 XML 的值来解决此问题:
SELECT STUFF((SELECT ',' + V.String
FROM (VALUES('7 > 5'),('Salt & pepper'),('2
lines'))V(String)
FOR XML PATH(''),TYPE).value('(./text())[1]','varchar(MAX)'),1,1,'');
Run Code Online (Sandbox Code Playgroud)
这将返回以下字符串:
7 > 5,Salt & pepper,2
lines
Run Code Online (Sandbox Code Playgroud)
这将复制以下行为:
SELECT STRING_AGG(V.String,',')
FROM VALUES('7 > 5'),('Salt & pepper'),('2
lines'))V(String);
Run Code Online (Sandbox Code Playgroud)
当然,有时您可能想要对数据进行分组,上面没有演示这一点。要实现此目的,您需要使用相关子查询。取以下样本数据:
CREATE TABLE dbo.MyTable (ID int IDENTITY(1,1),
GroupID int,
SomeCharacter char(1));
INSERT INTO dbo.MyTable (GroupID, SomeCharacter)
VALUES (1,'A'), (1,'B'), (1,'D'),
(2,'C'), (2,NULL), (2,'Z');
Run Code Online (Sandbox Code Playgroud)
由此想要得到以下结果:
组ID | 人物 |
---|---|
1 | 甲、乙、丁 |
2 | C、Z |
要实现这一目标,您需要执行以下操作:
SELECT MT.GroupID,
STUFF((SELECT ',' + sq.SomeCharacter
FROM dbo.MyTable sq
WHERE sq.GroupID = MT.GroupID --This is your correlated join and should be on the same columns as your GROUP BY
--You "JOIN" on the columns that would have been in the PARTITION BY
FOR XML PATH(''),TYPE).value('(./text())[1]','varchar(MAX)'),1,1,'')
FROM dbo.MyTable MT
GROUP BY MT.GroupID; --I use GROUP BY rather than DISTINCT as we are technically aggregating here
Run Code Online (Sandbox Code Playgroud)
因此,如果您对 2 列进行分组,那么您的子查询将有 2 个子句WHERE
: WHERE MT.SomeColumn = sq.SomeColumn AND MT.AnotherColumn = sq.AnotherColumn
,而您的外部子句GROUP BY
将是GROUP BY MT.SomeColumn, MT.AnotherColumn
。
最后,让我们添加一个到ORDER BY
其中,您也在子查询中定义它。例如,假设您想按ID
字符串聚合中的降序值对数据进行排序:
SELECT MT.GroupID,
STUFF((SELECT ',' + sq.SomeCharacter
FROM dbo.MyTable sq
WHERE sq.GroupID = MT.GroupID
ORDER BY sq.ID DESC --This is identical to the ORDER BY you would have in your OVER clause
FOR XML PATH(''),TYPE).value('(./text())[1]','varchar(MAX)'),1,1,'')
FROM dbo.MyTable MT
GROUP BY MT.GroupID;
Run Code Online (Sandbox Code Playgroud)
For 将产生以下结果:
组ID | 人物 |
---|---|
1 | D、B、A |
2 | Z、C |
毫不奇怪,这永远不会像 a 那样高效STRING_AGG
,因为多次引用表(如果需要执行多个聚合,则需要多个子查询),但是索引良好的表将极大地帮助 RDBMS。如果性能确实是一个问题,因为您在单个查询中进行多个字符串聚合,那么我建议您需要重新考虑是否需要聚合,或者是时候考虑升级了。
Gor*_*off 10
在2017年之前的SQL Server中,您可以执行以下操作:
select stuff( (select ',' + cast(t.id as varchar(max))
from tabel t
for xml path ('')
), 1, 1, ''
);
Run Code Online (Sandbox Code Playgroud)
唯一的目的stuff()
是删除最初的逗号.这项工作正在完成for xml path
.