Berikut adalah solusi menggunakan CTE rekursif. Saya menggunakan lvl
sebagai tajuk kolom sejak level
adalah kata yang dicadangkan di Oracle. Anda akan melihat perbedaan lain dalam terminologi juga. Saya menggunakan "induk" untuk level yang lebih tinggi dan "leluhur" untuk>=0 langkah (untuk mengakomodasi kebutuhan Anda untuk menunjukkan simpul sebagai leluhurnya sendiri). Saya menggunakan ORDER BY
klausa untuk menyebabkan output cocok dengan milik Anda; Anda mungkin atau mungkin tidak membutuhkan baris yang dipesan.
Pertanyaan Anda mendorong saya untuk membaca lagi, secara lebih rinci, tentang kueri hierarkis, untuk melihat apakah ini dapat dilakukan dengan mereka alih-alih CTE rekursif. Sebenarnya saya sudah tahu Anda bisa, dengan menggunakan CONNECT_BY_PATH
, tetapi menggunakan substr
pada itu hanya untuk mengambil tingkat atas dalam jalur hierarkis tidak memuaskan sama sekali, harus ada cara yang lebih baik. (Jika itu satu-satunya cara untuk melakukannya dengan kueri hierarkis, saya pasti akan menggunakan rute CTE rekursif jika tersedia). Saya akan menambahkan solusi kueri hierarkis di sini, jika saya dapat menemukan solusi yang bagus.
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
Ditambahkan :Solusi kueri hierarki
Oke - menemukannya. Silakan uji kedua solusi untuk melihat mana yang berkinerja lebih baik; dari pengujian pada pengaturan yang berbeda, CTE rekursif sedikit lebih cepat daripada kueri hierarkis, tetapi itu mungkin tergantung pada situasi spesifik. JUGA:CTE rekursif hanya berfungsi di Oracle 11.2 dan di atasnya; solusi hierarki berfungsi dengan versi yang lebih lama.
Saya menambahkan sedikit lebih banyak data pengujian untuk mencocokkan 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