Her er en løsning ved hjælp af en rekursiv CTE. Jeg brugte lvl
som kolonneoverskrift siden level
er et reserveret ord i Oracle. Du vil også se andre forskelle i terminologi. Jeg bruger "forælder" for det umiddelbart højere niveau og "forfader" for>=0 trin (for at imødekomme dit krav om at vise en node som sin egen forfader). Jeg brugte en ORDER BY
klausul for at få outputtet til at matche dit; du har muligvis brug for rækkerne bestilt eller ikke.
Dit spørgsmål stimulerede mig til igen at læse mere detaljeret om hierarkiske forespørgsler for at se, om dette kan gøres med dem i stedet for rekursive CTE'er. Faktisk ved jeg allerede, at du kan, ved at bruge CONNECT_BY_PATH
, men ved at bruge en substr
på, at bare at hente det øverste niveau i en hierarkisk vej slet ikke er tilfredsstillende, må der være en bedre måde. (Hvis det var den eneste måde at gøre det på med hierarkiske forespørgsler, ville jeg helt sikkert gå den rekursive CTE-vej, hvis den var tilgængelig). Jeg vil tilføje den hierarkiske forespørgselsløsning her, hvis jeg kan finde en god.
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
Tilføjet :Hierarkisk forespørgselsløsning
OK - fandt det. Test venligst begge løsninger for at se, hvilken der klarer sig bedst; fra test på en anden opsætning var rekursiv CTE en del hurtigere end hierarkisk forespørgsel, men det kan afhænge af den specifikke situation. OGSÅ:rekursiv CTE virker kun i Oracle 11.2 og nyere; den hierarkiske løsning fungerer med ældre versioner.
Jeg tilføjede lidt flere testdata for at matche Anatoliys.
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