如何将组标识符组合成单个组?

Dan*_*her 1 sql sql-server graph-theory recursive-query

我有一个数据集如下:

;WITH CTE AS
( SELECT *
  FROM (VALUES
(1, 10, 20, 30)
(2, 10, 21, 31)
(3, 11, 21, 31)
(4, 12, 22, 32)
(5, 13, 23, 33)
(6, 14, 24, 33)
(7, 14, 25, 34)
(8, 15, 26, 36)
) AS MyValues(ID, GroupID1, GroupID2, GroupID3)
)
SELECT *
FROM CTE
Run Code Online (Sandbox Code Playgroud)

如何生成以下内容,将各个组折叠成一个组?

ID 单组ID
1 1
2 1
3 1
4 2
5 3
6 3
7 3
8 4

GMB*_*GMB 6

这是一个典型的图遍历问题,您想要构建id至少有一组公共的 s 岛。

我们可以首先对组进行逆透视以构建节点列表,并通过自连接生成边(边连接id共享同一组的边)。然后我们可以递归地遍历边缘,同时跟踪我们到达那里之前所遵循的路径。最后一步是按 id 聚合。

所以:

with 
    nodes as (
        select t.id, v.grp
        from mytable t
        cross apply ( values (t.GroupID1), (t.GroupID2), (t.GroupID3) ) v(grp)
    ),
    edges as (
        select distinct n1.id as id1, n2.id as id2
        from nodes n1
        inner join nodes n2 on n1.grp = n2.grp
    ),
    rec as (
        select id1, id2, cast(id1 as nvarchar(max)) as visited from edges
        union all
        select r.id1, e.id2, concat(r.visited, ',', e.id2)
        from rec r
        inner join edges e on e.id1 = r.id2
        where concat(',', r.visited, ',') not like concat('%,', e.id2, ',%')
    ),
    fin as (
        select id1, min(value) min_id
        from rec r
        cross apply string_split(r.visited, ',')
        group by id1
    )
select id1 as id, dense_rank() over(order by min_id) grp
from fin f
Run Code Online (Sandbox Code Playgroud)
ID
1 1
2 1
3 1
4 2
5 3
6 3
7 3
8 4

小提琴