我需要按一组值以及每组的所有匹配行号/id:s 对表进行分组。此操作必须在 SQL Server 2016 的范围内完成。
假设我有下表(地点):
身份证 | 国家 | 城市 |
---|---|---|
1 | 瑞典 | 斯德哥尔摩 |
2 | 挪威 | 奥斯陆 |
3 | 冰岛 | 雷克雅未克 |
4 | 瑞典 | 斯德哥尔摩 |
我想要的结果(没有大括号,因为 Stack Overflow 认为这是代码,阻止我发布):
身份证 | 杰森 |
---|---|
1,4 | “国家”:“瑞典”,“城市”:“斯德哥尔摩” |
2 | “国家”:“挪威”,“城市”:“奥斯陆” |
3 | “国家”:“冰岛”,“城市”:“雷克雅未克” |
在 SQL Server 2017 中,可以通过以下方式实现上述结果:
SELECT STRING_AGG(ID) ID, (SELECT Country, City FOR JSON PATH) Json
FROM Places GROUP BY Country, City
我使用下面的代码在 SQL Server 2016 中获得了类似的结果。 (但是以我实际的数据量和列数来说,这个解决方案太慢了。)
SELECT DISTINCT Country, City INTO #temp FROM Places
SELECT (SELECT ID From Places WHERE Country = P.Country AND City = P.City FOR JSON PATH) ID,
(SELECT Country, City FOR JSON Path) Json FROM #temp P
有没有更有效的方法来实现我所追求的结果?
编辑:正如人们建议我尝试“FOR XML Path”我尝试了下面的代码。这会出现以下错误“Places.ID 在选择列表中无效,因为它不包含在聚合函数或 GROUP BY 子句中”:
SELECT stuff((select ',' + cast(ID as varchar(max)) for xml path ('')), 1, 1, '') ID,
(SELECT Country, City FOR JSON PATH) Json
FROM Places GROUP BY Country, City
这是您可以尝试的解决方案
for xml path
基本上选择并分组所需的
json
列,并使用 apply
,使用 for xml path
解决方案聚合相关的 ID 值;因为外部查询需要引用 apply
的输出,它也需要聚合,所以我选择使用 max
select max(x.Ids), (select country,city for json path) as [Json]
from t
outer apply (
select Stuff((select ',' + Convert(varchar(10),t2.Id)
from t t2
where t2.city=t.city and t2.country=t.country
for xml path(''),type).value('(./text())[1]','varchar(10)'),1,1,'') as Ids
)x
group by country,city
这是另一种可能的解决方案:
Declare @testTable Table (ID int, Country varchar(30), City varchar(30));
Insert Into @testTable (ID, Country, City)
Values (1, 'Sweden', 'Stockholm')
, (2, 'Normway', 'Oslo')
, (3, 'Iceland', 'Reykjavik')
, (4, 'Sweden', 'Stockholm');
Select Distinct
ID = stuff((Select concat(',', tt2.ID)
From @testTable tt2
Where tt2.City = tt.City
And tt2.Country = tt.Country
For xml path (''), Type).value('.', 'varchar(10)'), 1, 1, '')
, json = (Select Country, City For JSON PATH)
From @testTable tt;
不知道这是否会表现得更好。本质上是一样的 - 只是使用 DISTINCT 而不是 GROUP BY。