Här är en lösning som använder en rekursiv CTE. Jag använde lvl
som kolumnrubrik sedan level
är ett reserverat ord i Oracle. Du kommer att se andra skillnader i terminologi också. Jag använder "förälder" för den omedelbart högre nivån och "förfader" för>=0 steg (för att tillgodose ditt krav på att visa en nod som sin egen förfader). Jag använde en ORDER BY
klausul för att få utdata att matcha din; du kanske behöver raderna ordnade eller inte.
Din fråga stimulerade mig att återigen läsa mer i detalj om hierarkiska frågor, för att se om detta kan göras med dem istället för rekursiva CTE. Jag vet faktiskt redan att du kan, genom att använda CONNECT_BY_PATH
, men med en substr
på att bara att hämta den översta nivån i en hierarkisk väg inte är tillfredsställande alls, det måste finnas ett bättre sätt. (Om det var det enda sättet att göra det med hierarkiska frågor, skulle jag definitivt gå den rekursiva CTE-vägen om den var tillgänglig). Jag kommer att lägga till den hierarkiska frågelösningen här, om jag kan hitta en bra.
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
Tillagt :Hierarkisk frågelösning
OK - hittade den. Testa båda lösningarna för att se vilken som fungerar bäst; från tester på en annan inställning var rekursiv CTE ganska mycket snabbare än hierarkisk fråga, men det kan bero på den specifika situationen. ÄVEN:rekursiv CTE fungerar endast i Oracle 11.2 och senare; den hierarkiska lösningen fungerar med äldre versioner.
Jag lade till lite mer testdata för att matcha 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