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

时间:2019-02-11 19:14:09

标签: sql sql-server uniqueidentifier recursive-query

首先,对于这个问题的主题不清楚或使用错误的术语,我深表歉意,但是我不确定我要做什么。我正在使用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

感谢,感谢您的帮助

-编辑后包含了我用来创建表格的代码

2 个答案:

答案 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