Oto rozwiązanie wykorzystujące rekurencyjne CTE. Użyłem lvl
jako nagłówek kolumny od level
jest słowem zastrzeżonym w Oracle. Zobaczysz również inne różnice w terminologii. Używam "rodzica" dla bezpośrednio wyższego poziomu i "przodka" dla>=0 kroków (aby dostosować się do wymagania pokazania węzła jako własnego przodka). Użyłem ORDER BY
klauzula powodująca, że dane wyjściowe będą pasować do twoich; możesz potrzebować zamówionych wierszy lub nie.
Twoje pytanie zachęciło mnie do ponownego, bardziej szczegółowego przeczytania o zapytaniach hierarchicznych, aby zobaczyć, czy można to zrobić z nimi zamiast z rekurencyjnymi CTE. Właściwie już wiem, że możesz, używając CONNECT_BY_PATH
, ale używając substr
pod tym względem samo odzyskanie najwyższego poziomu w ścieżce hierarchicznej wcale nie jest satysfakcjonujące, musi istnieć lepszy sposób. (Gdyby to był jedyny sposób na zrobienie tego z zapytaniami hierarchicznymi, zdecydowanie wybrałbym rekurencyjną ścieżkę CTE, gdyby była dostępna). Dodam tutaj hierarchiczne rozwiązanie zapytania, jeśli znajdę dobre.
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
Dodano :Hierarchiczne rozwiązanie zapytań
OK - znalazłem to. Przetestuj oba rozwiązania, aby zobaczyć, które działa lepiej; z testów na innej konfiguracji rekurencyjne CTE było nieco szybsze niż zapytania hierarchiczne, ale może to zależeć od konkretnej sytuacji. RÓWNIEŻ:rekurencyjne CTE działa tylko w Oracle 11.2 i nowszych; rozwiązanie hierarchiczne działa ze starszymi wersjami.
Dodałem trochę więcej danych testowych, aby dopasować dane Anatolija.
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