Рекурсивный запрос для поиска родительской записи

#sql #tsql #sql-server-2008

#sql #tsql #sql-server-2008

Вопрос:

На основе самого высокого уровня и для соответствующей записи дочернего идентификатора, т.Е. 71 здесь, мне нужно подняться на уровень до 1 и получить соответствующую запись дочернего идентификатора, т.е. 209

Например:

Чтобы найти дочернюю запись для 71:

родительский уровень 4 — 154, родительский уровень 3 — 192, родительский уровень 2 — 209 или дочерний уровень 1 — 209

209 — необходимый ответ.

Теперь сложная часть заключается в том, что самый высокий уровень является переменным. Мой запрос, показанный выше, не работает, поскольку уровень увеличивается до 6 или 7, поскольку я не буду знать количество необходимых соединений.

Можем ли мы легко сделать это в рекурсивном CTE?

 declare @t table (
 childID int,
 ParentID int,
 level int
)

insert into @t
select 71, 154, 4
union
select 154, 192, 3
union
select 192, 209, 2
union
select 209, 0, 1

select * from @t

select t1.childID, t4.ChildID
from @t t1
inner join
@t t2
on t1.ParentID = t2.childID
inner join
@t t3
on t2.ParentID = t3.childID
inner join
@t t4
on t3.ParentID = t4.childID
and t1.childID = 71
  

-- I tried to with recursive CTE

 -- I need to get 71, 209 but getting 209, 0


  ;with MyCTE as
    (
    select childID, ParentID from @t t1 
    where t1.level = 1
    UNION ALL
    select m.childID, t2.childID from @t t2
    inner join
    MyCTE m
    on m.childID = t2.ParentID
    )
select top 1 * from MyCTE
  

Ответ №1:

Попробуйте это:

 declare @t table (
 childID int,
 ParentID int,
 level int
)

insert into @t
select 71, 154, 4
union
select 154, 192, 3
union
select 192, 209, 2
union
select 209, 0, 1

Declare @SearchChild int
set @SearchChild=71

  ;with MyCTE as (
      select t1.childID, t1.ParentID , @SearchChild AS searchChild, t1.level
        from @t t1 
        where t1.childID = @SearchChild
      UNION ALL
      select t1.childID, t1.ParentID , c.SearchChild, t1.level
        from @t t1
        inner join MyCTE c on t1.childID=c.ParentID
  )
select top 1 * from MyCTE order by level asc
  

ВЫВОД:

 childID     ParentID    searchChild level
----------- ----------- ----------- -----------
209         0           71          1
  

Я не уверен, что вам нужно, нет строки, в которой 209 и 71 вместе? это лучшее, что вы можете сделать. Кроме того, этот CTE работает вверх по цепочке, а не вниз, и должен работать намного лучше на больших таблицах.

Ответ №2:

Это способ сделать это:

 ;with MyCTE as
(
    select childID, ParentID, t1.childID As firstChild, 0 As depth
    from @t t1 
    where t1.level = 1

    UNION ALL

    select t2.childID, t2.ParentID, m.firstChild, m.depth   1
    from @t t2
    inner join MyCTE m
    on m.childID = t2.ParentID
)
select TOP 1 childID, firstChild  
from MyCTE
ORDER BY depth DESC
  

Дает вам

 childId firstChild
71      209
  

Комментарии:

1. не будет работать, если в таблице более одной цепочки, что, я думаю, наиболее вероятно.

2. @KM. Похоже, что он настроен как связанный список

3. тестовые данные представляют собой единую цепочку, но я буду фактическими данными таблицы, содержащими много. Начиная с уровня 1, вам нужно будет обработать все цепочки, чтобы найти 71 дочернюю запись. Однако, если вы начнете с 71 дочернего элемента и вернетесь к первому уровню, как я делаю в своем ответе, вы найдете его быстрее, и несколько цепочек не повлияют на результат.