Nos*_*iki 4 sql-server group-by group-concatenation sql-server-2014
我正在运行 SQL Server 2014
我有一个看起来像这样的表:
ID | Name | AddressType | Address | Features
========================================================
1 | Bob | Home | 123 Nope St | JP
2 | John | Work | 555 Fake St | MNGF
2 | John | Home | 654 Madeup Ln | IMP JP
3 | Kim | Work | 92 Nadda Blvd | MP
Run Code Online (Sandbox Code Playgroud)
我正在尝试编写一个 SQL Server 查询来查找重复的 ID,并始终返回包含“工作”地址的行,但我希望它将两行中的功能连接起来,以便得到如下所示的结果:
ID | Name | AddressType | Address | Features
========================================================
1 | Bob | Home | 123 Nope St | JP
2 | John | Work | 555 Fake St | MNGF IMP JP
3 | Kim | Work | 92 Nadda Blvd | MP
Run Code Online (Sandbox Code Playgroud)
我能弄清楚如何得到的最接近的看起来像这样:
SELECT ID, Name, MAX(AddressType), MAX(Address), CONCAT(Features) FROM
(SELECT * FROM myTable ORDER BY ID, AddressType DESC)
GROUP BY ID, NAME
Run Code Online (Sandbox Code Playgroud)
...但是 MAX(AddressType) 和 MAX(Address) 是分开拉取的,所以有时我得到工作地址,有时我得到家庭地址。我真正需要的是 MAX(AddressType) 以及与该结果位于同一行的任何地址。
我尝试过的另一件事是:
SELECT ID, Name, AddressType, Address, CONCAT(Features), COUNT(ID) OVER(PARTITION BY ID) AS IDcount
FROM myTable
GROUP BY ID, NAME
WHERE AddressType = 'Work' OR IDcount = 1
Run Code Online (Sandbox Code Playgroud)
...这总是为我提供所有正确的地址,但过滤掉“Home”AddressType 的功能,以便我无法将它们连接起来。
如果您使用的是 SQL Server 2017 或更高版本,则可以使用 STRING_AGG 函数来连接组内的值。
然后,您可以使用 CTE 单独获取功能列表以简化查询,然后将其连接回数据以获得所需的行以及每个 ID 的完整功能列表。
脚本:
;WITH AddressFeatures AS
(
SELECT ID, STRING_AGG(Features, ' ') AS Features
FROM Addresses
GROUP BY ID
)
SELECT s1.ID, s1.Name, s1.AddressType, s1.Address, af.Features
FROM
(
SELECT ID, Name, AddressType, Address
, ROW_NUMBER()
OVER (PARTITION BY ID
ORDER BY
CASE WHEN AddressType = 'Work' THEN 1 ELSE 2 END)
AS AddressTypeOrder
FROM Addresses
) s1
INNER JOIN AddressFeatures af ON af.ID = s1.ID
WHERE AddressTypeOrder = 1
Run Code Online (Sandbox Code Playgroud)
输出:
ID | 姓名 | 地址类型 | 地址 | 特征 |
---|---|---|---|---|
1 | 鲍勃 | 家 | 123 诺普街 | J.P |
2 | 约翰 | 工作 | 第555章假圣 | MNGF IMP 日本 |
3 | 金 | 工作 | 纳达大道92号 | 国会议员 |
您可以在此db<>fiddle中看到一个工作示例。
此方法的优点是,您可以使用多个地址类型值,并通过简单地将 WHEN 子句添加到内部 SELECT 语句中 ROW_NUMBER() 函数中的 CASE 语句来根据您所需的逻辑对它们进行排序。
更新:对于 SQL 2017 之前的版本,您可以使用 STUFF 和 FOR XML 的组合来复制 STRING_AGG 的行为:
;WITH AddressFeatures AS
(
SELECT ID,
(SELECT STUFF((
SELECT ' ' + a2.[Features]
FROM Addresses a2
WHERE a1.ID = a2.ID
FOR XML PATH ('')), 1, 1, '')) AS Features
FROM Addresses a1
GROUP BY ID
)
SELECT s1.ID, s1.Name, s1.AddressType, s1.Address, af.Features
FROM
(
SELECT ID, Name, AddressType, Address
, ROW_NUMBER() OVER
(PARTITION BY ID
ORDER BY CASE WHEN AddressType = 'Work' THEN 1 ELSE 2 END)
AS AddressTypeOrder
FROM Addresses
) s1
INNER JOIN AddressFeatures af ON af.ID = s1.ID
WHERE AddressTypeOrder = 1
Run Code Online (Sandbox Code Playgroud)
请参阅更新的数据库<>摆弄此解决方案。从功能上讲,其行为相同,但性能可能会受到影响。
归档时间: |
|
查看次数: |
20479 次 |
最近记录: |