首先,对于这个问题的主题不清楚或使用错误的术语,我深表歉意,但是我不确定我要做什么。我正在使用SQL Server2016。我有一个包含以下三列的表:
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
感谢,感谢您的帮助
-编辑后包含了我用来创建表格的代码
答案 0 :(得分:0)
这是一个图形行走问题。以下应该获取每个连接组的最小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 <>小提琴。
答案 1 :(得分:0)
感谢@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