我有一个类似于这个定义的PostgreSQL表:
CREATE TABLE tname(
id bigserial PRIMARY KEY,
name TEXT,
parent_id bigint,
FOREIGN KEY (parent_id) REFERENCES tname (id)
);
考虑以下示例
id | name | parent_id
-------------------------
1 | 'root' | NULL
2 | 'child1' | 1
3 | 'child2' | 1
4 | 'child1' | 2
5 | 'child2' | 2
我需要我的程序根据路径生成查询,例如' root / child1 / child2' 这应该返回id 5的行。
我提出了一个有点工作的查询,但我怀疑它不是最优的,并认为它可以更好地解决。
WITH root AS (
SELECT id, name, parent_id
FROM tname
WHERE tname.parent_id IS NULL
AND tname.name = 'root'
), b1 AS (
SELECT id, name, parent_id
FROM tname
WHERE tname.parent_id IN (SELECT id FROM root)
AND tname.name = 'child1'
), b2 AS (
SELECT id, name, parent_id
FROM tname
WHERE tname.parent_id IN (SELECT id FROM b1)
AND tname.name = 'child2'
)
SELECT *
FROM tname
WHERE id IN (SELECT id FROM b2)
我觉得这是一个非常流行的解决方案,随着路径的增长将会很长。
我如何以更优化的方式解决这个问题?可以使用RECURSIVE查询,它会更快吗?
答案 0 :(得分:0)
是的,当然可以使用递归,它不一定会更快,但更容易阅读和使用。您的表格布局非常常见,但是,如果您考虑放入一个“路径”字段来帮助这样的查询以使其更快并且能够使用索引,那么查询会更容易。
这是一个递归查询的示例,它比您的示例更容易:
with recursive ret(id, parent_id, path) as
(
select t.id,t.parent_id, '\' as path from tname t
where t.parent_id is null
union
select t.id, t.parent_id, ret.path||t.name||'\' as pth from tname t
inner join ret on ret.id=t.parent_id
)
select id, parent_id, path from ret
where path='\my\path\'