Hier is een oplossing met een recursieve CTE. Ik gebruikte lvl
als kolomkop sinds level
is een gereserveerd woord in Oracle. U zult ook andere verschillen in terminologie zien. Ik gebruik "ouder" voor het onmiddellijk hogere niveau en "voorouder" voor>=0 stappen (om tegemoet te komen aan uw vereiste om een knooppunt als zijn eigen voorouder te tonen). Ik gebruikte een ORDER BY
clausule om ervoor te zorgen dat de uitvoer overeenkomt met die van u; u kunt de bestelde rijen wel of niet nodig hebben.
Uw vraag stimuleerde me om opnieuw, in meer detail, over hiërarchische queries te lezen, om te zien of dit hiermee kan worden gedaan in plaats van recursieve CTE's. Eigenlijk weet ik al dat je dat kunt, door CONNECT_BY_PATH
. te gebruiken , maar met een substr
op dat alleen maar het hoogste niveau in een hiërarchisch pad te halen is helemaal niet bevredigend, er moet een betere manier zijn. (Als dat de enige manier was om het te doen met hiërarchische zoekopdrachten, zou ik zeker de recursieve CTE-route gaan als deze beschikbaar was). Ik zal de hiërarchische zoekoplossing hier toevoegen, als ik een goede kan vinden.
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
Toegevoegd :Hiërarchische zoekoplossing
Oké - gevonden. Test beide oplossingen om te zien welke beter presteert; van tests op een andere setup was recursieve CTE een stuk sneller dan hiërarchische query's, maar dat kan van de specifieke situatie afhangen. OOK:recursieve CTE werkt alleen in Oracle 11.2 en hoger; de hiërarchische oplossing werkt met oudere versies.
Ik heb wat meer testgegevens toegevoegd die overeenkomen met die van Anatoliy.
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