История записей трассировки SQL с использованием полей идентификаторов - PullRequest
0 голосов
/ 11 февраля 2019

Во-первых, я прошу прощения, если предмет этого вопроса не ясен или использует неправильную терминологию, но я не совсем уверен, что то, что я пытаюсь сделать, называется.Я использую 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 в порядке возрастания, потому что 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 голосов
/ 12 февраля 2019

Спасибо @Gordon Linoff за указание правильного направления при обходе графа, которое привело меня к этому посту по рекурсивным запросам SQL SERVER - Введение в иерархический запрос с использованием рекурсивного CTE - Учебник для начинающих

Я понял, что мне не нужно смотреть в обоих направлениях для каждой записи, чтобы получить историю записей, так как каждая запись будет иметь «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
0 голосов
/ 11 февраля 2019

Это проблема обхода графа.Следующее должно получить минимальный идентификатор для каждой подключенной группы.

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 вернуться к исходным данным, чтобы назначить группу исходным строкам.

Здесь - это дБ <> скрипка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...