Đây là một giải pháp sử dụng CTE đệ quy. Tôi đã sử dụng lvl
làm tiêu đề cột kể từ level
là một từ dành riêng trong Oracle. Bạn cũng sẽ thấy những khác biệt khác về thuật ngữ. Tôi sử dụng "cha" cho cấp cao hơn ngay lập tức và "tổ tiên" cho> =0 bước (để đáp ứng yêu cầu của bạn về việc hiển thị một nút làm tổ tiên của nó). Tôi đã sử dụng ORDER BY
mệnh đề khiến đầu ra khớp với kết quả của bạn; bạn có thể cần hoặc không cần các hàng được sắp xếp.
Câu hỏi của bạn đã kích thích tôi đọc lại, chi tiết hơn, về các truy vấn phân cấp, để xem liệu điều này có thể được thực hiện với chúng thay vì các CTE đệ quy hay không. Trên thực tế, tôi biết bạn có thể làm được, bằng cách sử dụng CONNECT_BY_PATH
, nhưng sử dụng substr
trên đó chỉ để truy xuất cấp cao nhất trong một đường dẫn phân cấp là không thỏa mãn chút nào, phải có một cách tốt hơn. (Nếu đó là cách duy nhất để làm điều đó với các truy vấn phân cấp, tôi chắc chắn sẽ đi theo tuyến CTE đệ quy nếu nó có sẵn). Tôi sẽ thêm giải pháp truy vấn phân cấp ở đây, nếu tôi có thể tìm thấy giải pháp tốt.
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
Đã thêm :Giải pháp truy vấn phân cấp
OK - đã tìm thấy nó. Vui lòng kiểm tra cả hai giải pháp để xem giải pháp nào hoạt động tốt hơn; từ các thử nghiệm trên một thiết lập khác, CTE đệ quy nhanh hơn một chút so với truy vấn phân cấp, nhưng điều đó có thể phụ thuộc vào tình huống cụ thể. CŨNG CÓ:CTE đệ quy chỉ hoạt động trong Oracle 11.2 trở lên; giải pháp phân cấp hoạt động với các phiên bản cũ hơn.
Tôi đã thêm một chút dữ liệu thử nghiệm để khớp với Anatoliy's.
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