Проблема с обходом таблицы закрытия с помощью CTE - PullRequest
0 голосов
/ 24 февраля 2020

У меня есть эта таблица замыканий, и я хотел бы вывести все узлы транзитивно. Но у меня проблемы с тем, чтобы заставить это работать. Я впервые использую CTE, поэтому я не знаю, как мне это сделать.

Вот мои relations_table :

+-----+-------------+---------------+-------+------+
| id  | ancestor_id | descendant_id | depth | type |
+-----+-------------+---------------+-------+------+
| 207 |          86 |            86 |     0 |    1 |
| 208 |          87 |            87 |     0 |    1 |
| 209 |          86 |            87 |     1 |    1 |
| 210 |          88 |            88 |     0 |    1 |
| 211 |          86 |            88 |     2 |    1 |
| 212 |          87 |            88 |     1 |    1 |
| 213 |          89 |            89 |     0 |    1 |
| 214 |          87 |            89 |     1 |    1 |
| 215 |          86 |            89 |     2 |    1 |
| 216 |          90 |            90 |     0 |    1 |
| 217 |          86 |            90 |     1 |    1 |
| 218 |          91 |            91 |     0 |    1 |
| 219 |          86 |            91 |     1 |    1 |
| 220 |          92 |            92 |     0 |    1 |
| 221 |          90 |            92 |     1 |    1 |
| 222 |          86 |            92 |     2 |    1 |
| 223 |          93 |            93 |     0 |    1 |
| 224 |          90 |            93 |     1 |    1 |
| 225 |          86 |            93 |     2 |    1 |
+-----+-------------+---------------+-------+------+

Как мне написать запрос, который выбирает узлы транзитивно из root с помощью CTE. Я продолжаю зацикливаться на этом.

1 Ответ

1 голос
/ 24 февраля 2020
declare @t table
(
id  int,
ancestor_id int,
descendant_id int,
depth int,
type int
);

insert into @t(id, ancestor_id, descendant_id, depth, type)
values
(207 , 86 , 86 , 0 ,  1),
(208 , 87 , 87 , 0 ,  1),
(209 , 86 , 87 , 1 ,  1),
(210 , 88 , 88 , 0 ,  1),
(211 , 86 , 88 , 2 ,  1),
(212 , 87 , 88 , 1 ,  1),
(213 , 89 , 89 , 0 ,  1),
(214 , 87 , 89 , 1 ,  1),
(215 , 86 , 89 , 2 ,  1),
(216 , 90 , 90 , 0 ,  1),
(217 , 86 , 90 , 1 ,  1),
(218 , 91 , 91 , 0 ,  1),
(219 , 86 , 91 , 1 ,  1),
(220 , 92 , 92 , 0 ,  1),
(221 , 90 , 92 , 1 ,  1),
(222 , 86 , 92 , 2 ,  1),
(223 , 93 , 93 , 0 ,  1),
(224 , 90 , 93 , 1 ,  1),
(225 , 86 , 93 , 2 ,  1);

with cte
as
(
    select ancestor_id as childid, cast(null as int) as parentid, ancestor_id as rootid, 0 as lvl
    from
    (
        --roots, top level parents (they are not chilren/descendants)
        select ancestor_id
        from @t
        except
        select descendant_id
        from @t
        where descendant_id <> ancestor_id
    ) as p
    union all
    select t.descendant_id, t.ancestor_id, c.rootid, c.lvl+1
    from cte as c
    join @t as t on c.childid = t.ancestor_id and t.ancestor_id <> t.descendant_id
)
select *
from cte;


--the full hierarchy of each child is logged in @t, for each parent get the list of children without cte
select ancestor_id as parentid, stuff(c.children_concat, 1, 1, '') as children_list
from
(
    --parents
    select distinct ancestor_id
    from @t
) as p
outer apply
(
    select
    (
    select distinct ',' + cast(t.descendant_id as varchar(20))
    from @t as t
    where t.ancestor_id = p.ancestor_id
    and t.descendant_id <> p.ancestor_id
    order by ',' + cast(t.descendant_id as varchar(20)) --desc
    for xml path('')
    ) as children_concat
) as c;
...