Sử dụng biểu thức bảng chung đệ quy
. Luôn bắt đầu từ gốc, sử dụng một mảng id để lấy đường dẫn cho một id
nhất định trong WHERE
mệnh đề.
Đối với id = 1
:
with recursive cte(id, parent, name, ids) as (
select id, parent, name, array[id]
from my_table
where parent is null
union all
select t.id, t.parent, concat(c.name, t.name, '/'), ids || t.id
from cte c
join my_table t on c.id = t.parent
)
select id, name
from cte
where 1 = any(ids) and id <> 1
id | name
----+-----------------------
2 | /home/
5 | /usr/
6 | /usr/local/
3 | /home/user/
4 | /home/user/bin/
(5 rows)
Đối với id = 2
:
with recursive cte(id, parent, name, ids) as (
select id, parent, name, array[id]
from my_table
where parent is null
union all
select t.id, t.parent, concat(c.name, t.name, '/'), ids || t.id
from cte c
join my_table t on c.id = t.parent
)
select id, name
from cte
where 2 = any(ids) and id <> 2
id | name
----+-----------------------
3 | /home/user/
4 | /home/user/bin/
(2 rows)
Truy vấn hai chiều
Câu hỏi thực sự thú vị. Truy vấn trên hoạt động tốt nhưng không hiệu quả vì nó phân tích cú pháp tất cả các nút cây ngay cả khi chúng tôi yêu cầu một lá. Giải pháp mạnh mẽ hơn là truy vấn đệ quy hai chiều. Truy vấn bên trong đi từ một nút nhất định lên trên cùng, trong khi truy vấn bên ngoài đi từ nút xuống dưới cùng.
with recursive outer_query(id, parent, name) as (
with recursive inner_query(qid, id, parent, name) as (
select id, id, parent, name
from my_table
where id = 2 -- parameter
union all
select qid, t.id, t.parent, concat(t.name, '/', q.name)
from inner_query q
join my_table t on q.parent = t.id
)
select qid, null::int, right(name, -1)
from inner_query
where parent is null
union all
select t.id, t.parent, concat(q.name, '/', t.name)
from outer_query q
join my_table t on q.id = t.parent
)
select id, name
from outer_query
where id <> 2; -- parameter