首先,如果这个问题的主题不清楚或使用的是错误的术语,我会道歉,但我不太确定我要做的是什么。我正在使用SQL Server 2016.我有一个表,其中包含以下三列:
create table #temp (PrevID varchar(10),ID varchar(10), NextID varchar(10))
insert into #temp
Select NULL,'ABC1','ABC3' Union all
Select NULL,'ABC2','ABC4' Union all
Select 'ABC1','ABC3','ABC9' Union all
Select 'ABC2','ABC4','ABC10' Union all
Select 'ABC3','ABC9',NULL Union all
Select 'ABC4','ABC10','ABC25' Union all
Select 'ABC10','ABC25',NULL
PrevID |ID | NextID
NULL |ABC1 | ABC3
NULL |ABC2 | ABC4
ABC1 |ABC3 | ABC9
ABC2 |ABC4 | ABC10
ABC3 |ABC9 | NULL
ABC4 |ABC10| ABC25
ABC10 |ABC25| NULL
我想要做的是得到彼此相关的ID的输出。我不能简单地按ID按升序排序,因为ABC1和ABC2是两个不同链的一部分,而每个链是连续的,它们不是连续的。
通常情况下,我会使用CTE或子查询来自动加入表,以便能够查询下一个或以前的记录,但是对链条的一部分有多少记录没有特定的限制,因此我事先无法知道我需要重新加入桌子的次数。不幸的是,我也无法更改表的结构以添加ChainID。
所需的输出将如下所示:
ChainID|PrevID |ID | NextID
Chain1 |NULL |ABC1 | ABC3
Chain1 |ABC1 |ABC3 | ABC9
Chain1 |ABC3 |ABC9 | NULL
Chain2 |NULL |ABC2 | ABC4
Chain2 |ABC2 |ABC4 | ABC10
Chain2 |ABC4 |ABC10| ABC25
Chain2 |ABC10 |ABC25| NULL
谢谢,我感谢任何帮助
- 编辑包含我用于创建表格的代码
这是图形行走问题。以下内容应获取每个连接组的最小ID。
with edges as (
select distinct v.id1, v.id2
from t cross apply
(values (prev_id, id), (id, prev_id), (next_id, id), (id, next_id)
) v(id1, id2)
where id1 is not null and id2 is not null
),
cte as (
select id1, id1 as id2,
convert(varchar(max), concat(',', id1, ',')) as ids
from edges
union all
select cte.id1, e.id2,
concat(ids, e.id2 + ',')
from cte join
edges e
on cte.id2 = e.id1
where cte.ids not like concat('%,', e.id2, ',%')
)
select id1, min(id2) as grp, dense_rank() over (order by min(id2)) as grp_num
from cte
group by id1;
然后,您可以将join
返回到原始数据,以将组分配给原始行。
Here是一个db <>小提琴。
感谢@Gordon Linoff指出我正确的方向与图形走路导致我在递归查询SQL SERVER – Introduction to Hierarchical Query using a Recursive CTE – A Primer这篇文章
我意识到我并不是真的需要在每个记录的两个方向上查看记录的历史记录,因为每个记录都有一个“NextID”,直到最后一个将是NULL我可以从基本记录向前跟随它。我想出了下面的查询,它在不到一秒的时间内完成了我的~700行样本测试。
create table #temp (PrevID varchar(10),ID varchar(10), NextID varchar(10))
insert into #temp
Select NULL,'ABC1','ABC3' Union all
Select NULL,'ABC2','ABC4' Union all
Select 'ABC1','ABC3','ABC9' Union all
Select 'ABC2','ABC4','ABC10' Union all
Select 'ABC3','ABC9',NULL Union all
Select 'ABC4','ABC10','ABC25' Union all
Select 'ABC10','ABC25',NULL
;
with descendants as
( select id as ParentID, nextid as ChildID, 2 as rn
from #temp
union all
select d.ParentID, s.nextid, d.rn + 1
from descendants as d
join #temp s on d.ChildID = s.id
)
select *
from descendants a
where not exists
(select distinct d.ChildID
from descendants d
where d.ChildID = a.ParentID)
and ChildID is not null
union all
select id,id, 1
from #temp t
where t.previd is null
order by 1,3