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 |
这是一个典型的图遍历问题,您想要构建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 |
| 归档时间: |
|
| 查看次数: |
129 次 |
| 最近记录: |