我遇到了一个有趣的场景,试图将任意 FamilyId
分配给彼此相关的字段。
这是我们当前正在使用的结构:
DataId OriginalDataId
3 1
4 1
5 1
6 1
3 2
4 2
5 2
6 2
7 10
8 10
9 10
11 15
我们尝试做的是将 FamilyId
列添加到所有彼此之间有关系的 DataId
中。
在本例中,Id 的 3
、4
、5
和 6
与 存在关系>1
。但3
、4
、5
和6
也与2
有关系。因此 1
、2
、3
、4
、5
和 6
应被视为位于同一 FamilyId
中。
7
、8
和 9
仅与 10
有关系,这会将其放入单独的FamilyId
。 11
和 15
相同。
我期望得到以下结果:
DataId FamilyId
1 1
2 1
3 1
4 1
5 1
6 1
7 2
8 2
9 2
10 2
11 3
15 3
示例数据、结构和查询:
Declare @Results_Stage Table
(
DataId BigInt Not Null,
OriginalDataId BigInt Null
)
Insert @Results_Stage
Values (3,1), (4,1), (5,1), (6,1), (3,2), (4,2), (5,2), (6,2), (7,10), (8, 10), (9, 10), (11, 15)
Select DataId, Row_Number() Over(Partition By DataId Order By OriginalDataId Asc) FamilyId
From @Results_Stage R
Union
Select OriginalDataId, Row_Number() Over(Partition By DataId Order By OriginalDataId Asc) FamilyId
From @Results_Stage
我确信我的尝试远不正确,但老实说我不确定从哪里开始——或者在 SQL Server 中是否可能。
有人知道如何解决这个问题,或者至少能指出正确的方向吗?
编辑 下面是我迄今为止提出的一个查询,用于识别应属于同一 FamilyId
的其他 DataId
记录
Declare @DataId BigInt = 1
;With Children As
(
Select Distinct X.DataId
From @Results_Stage S
Outer Apply
(
Select Distinct DataId
From @Results_Stage R
Where R.OriginalDataId = S.DataId
Or R.OriginalDataId = S.OriginalDataId
) X
Where S.DataId = @DataId
Or S.OriginalDataId = @DataId
)
Select Distinct O.OriginalDataId
From Children C
Outer Apply
(
Select S.OriginalDataId
From @Results_Stage S
Where S.DataId = C.DataId
) O
Union
Select DataId
From Children
最佳答案
以下查询使用 FOR XML PATH
:
SELECT R.OriginalDataId,
STUFF((
SELECT ', ' + + CAST([DataId] AS VARCHAR(MAX))
FROM #Results_Stage
WHERE (OriginalDataId = R.OriginalDataId)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS GroupValues
FROM #Results_Stage R
GROUP BY R.OriginalDataId
可用于产生以下输出:
OriginalDataId GroupValues
===========================
1 3, 4, 5, 6
2 3, 4, 5, 6
10 7, 8, 9
15 11
使用上面的结果集,我们可以轻松识别每个组,从而获得可以应用 DENSE_RANK()
的内容:
;WITH GroupedData AS (
SELECT R.OriginalDataId,
STUFF((
SELECT ', ' + + CAST([DataId] AS VARCHAR(MAX))
FROM #Results_Stage
WHERE (OriginalDataId = R.OriginalDataId)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS GroupValues
FROM #Results_Stage R
GROUP BY R.OriginalDataId
), Families AS (
SELECT OriginalDataId, DENSE_RANK() OVER (ORDER BY GroupValues) AS FamilyId
FROM GroupedData
)
SELECT OriginalDataId AS DataId, FamilyId
FROM Families
UNION
SELECT DataId, F.FamilyId
FROM #Results_Stage R
INNER JOIN Families F ON R.OriginalDataId = F.OriginalDataId
ORDER BY FamilyId
上面的输出是:
DataId FamilyId
===================
11 1
15 1
1 2
2 2
3 2
4 2
5 2
6 2
7 3
8 3
9 3
10 3
关于SQL Server 为相关记录创建分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28155017/