SQL 使用 ID 字段跟踪记录历史

SQL Trace record history using ID fields

首先,如果这个问题的主题不清楚或使用了错误的术语,我深表歉意,但我不太确定我正在尝试做的事情叫什么。我正在使用 SQL Server 2016。我有一个 table,其中包含以下三列:

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 或子查询将 table 加入自身,以便能够查询下一条或上一条记录,但是对于有多少条记录将成为一个记录的一部分没有具体限制链,所以我无法提前知道我需要重新加入 table 的次数。不幸的是,我也无法更改 table 的结构来添加 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

谢谢,感谢任何帮助

-- 编辑以包括我用来创建 table 的代码,例如

这是一个图行走问题。以下应获取每个连接组的最小 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<>fiddle.

感谢@Gordon Linoff 用图表行走为我指明了正确的方向,这让我在递归查询 post SQL SERVER – Introduction to Hierarchical Query using a Recursive CTE – A Primer

上找到了这个 post

我意识到我真的不需要双向查看每条记录来获取记录的历史记录,因为每条记录都会有一个 "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