Ето решение, използващо рекурсивен CTE. Използвах lvl
като заглавка на колона от level
е запазена дума в Oracle. Ще видите и други разлики в терминологията. Използвам "родител" за непосредствено по-високото ниво и "предшественик" за>=0 стъпки (за да отговоря на вашето изискване за показване на възел като собствен предшественик). Използвах ORDER BY
клауза, която да накара изхода да съвпадне с вашия; може или не може да имате нужда от подредените редове.
Вашият въпрос ме стимулира да прочета отново, по-подробно, за йерархичните заявки, за да видя дали това може да се направи с тях вместо с рекурсивни CTE. Всъщност вече знам, че можете, като използвате CONNECT_BY_PATH
, но използвайки substr
относно това просто извличането на най-високото ниво в йерархичен път изобщо не е удовлетворяващо, трябва да има по-добър начин. (Ако това беше единственият начин да го направя с йерархични заявки, определено бих избрал рекурсивния CTE маршрут, ако беше наличен). Ще добавя решението за йерархична заявка тук, ако мога да намеря добро.
with h ( node, parent ) as (
select 1 , null from dual union all
select 2 , 1 from dual union all
select 3 , 2 from dual
),
r ( node , ancestor, steps ) as (
select node , node , 0
from h
union all
select r.node, h.parent, steps + 1
from h join r
on h.node = r.ancestor
)
select node, ancestor,
1+ (max(steps) over (partition by node)) as lvl, steps
from r
where ancestor is not null
order by lvl, steps desc;
NODE ANCESTOR LVL STEPS
---------- ---------- ---------- ----------
1 1 1 0
2 1 2 1
2 2 2 0
3 1 3 2
3 2 3 1
3 3 3 0
Добавено :Решение за йерархична заявка
Добре - намерих го. Моля, тествайте и двете решения, за да видите кое се представя по-добре; от тестове на различна настройка, рекурсивният CTE беше доста по-бърз от йерархичната заявка, но това може да зависи от конкретната ситуация. СЪЩО:рекурсивният CTE работи само в Oracle 11.2 и по-нови версии; йерархичното решение работи с по-стари версии.
Добавих малко повече тестови данни, за да съответстват на тези на Анатолий.
with h ( node, parent ) as (
select 1 , null from dual union all
select 2 , 1 from dual union all
select 3 , 2 from dual union all
select 4 , 2 from dual union all
select 5 , 4 from dual
)
select node,
connect_by_root node as ancestor,
max(level) over (partition by node) as lvl,
level - 1 as steps
from h
connect by parent = prior node
order by node, ancestor;
NODE ANCESTOR LVL STEPS
---------- ---------- ---------- ----------
1 1 1 0
2 1 2 1
2 2 2 0
3 1 3 2
3 2 3 1
3 3 3 0
4 1 3 2
4 2 3 1
4 4 3 0
5 1 4 3
5 2 4 2
5 4 4 1
5 5 4 0