Zde je řešení pomocí rekurzivního CTE. Použil jsem lvl
jako záhlaví sloupce od level
je vyhrazené slovo v Oracle. Uvidíte i další rozdíly v terminologii. Používám „rodič“ pro bezprostředně vyšší úroveň a „předek“ pro>=0 kroků (abych vyhověl vašemu požadavku na zobrazení uzlu jako jeho vlastního předka). Použil jsem ORDER BY
klauzule způsobí, že výstup bude odpovídat vašemu; můžete nebo nemusíte potřebovat objednané řádky.
Vaše otázka mě podnítila, abych si znovu přečetl podrobněji o hierarchických dotazech, abych zjistil, zda to lze provést s nimi namísto rekurzivních CTE. Vlastně už vím, že můžete pomocí CONNECT_BY_PATH
, ale pomocí substr
na to, že jen získat nejvyšší úroveň v hierarchické cestě není vůbec uspokojivé, musí existovat lepší způsob. (Pokud by to byl jediný způsob, jak to udělat s hierarchickými dotazy, určitě bych šel rekurzivní cestou CTE, pokud by byla k dispozici). Přidám zde hierarchické řešení dotazu, pokud najdu dobré.
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
Přidáno :Hierarchické řešení dotazů
OK - našel. Vyzkoušejte prosím obě řešení, abyste zjistili, které funguje lépe; z testů na jiném nastavení byl rekurzivní CTE o něco rychlejší než hierarchický dotaz, ale to může záviset na konkrétní situaci. TAKÉ:rekurzivní CTE funguje pouze v Oracle 11.2 a vyšší; hierarchické řešení funguje se staršími verzemi.
Přidal jsem trochu více testovacích dat, aby odpovídaly Anatoliymu.
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