SQL Server 为相关记录创建分组

标签 sql sql-server-2012 grouping

我遇到了一个有趣的场景,试图将任意 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 的 3456 存在关系>1。但3456也与2有关系。因此 12345 6 应被视为位于同一 FamilyId 中。

789 仅与 10 有关系,这会将其放入单独的FamilyId1115 相同。

我期望得到以下结果:

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/

相关文章:

java - 如何在teradata中执行多个查询?

sql-server - SQL Server 2012 和存储在一处的不同数据类型

SQL Server 2012 临时表 OBJECT_ID 问题

将具有单个后继节点的树节点分组的算法

sql - 从数字序列动态创建范围

sql - 查询在sql中按行排序

php - 使用命名参数在我的 SQL 中找不到错误

sql - 查询以计算每列的相似值

r - 按组划分数据列

javascript - 循环遍历数组并分配新数组的键