Postgresql查询获取路径中的最后一个节点

时间:2014-12-28 19:09:16

标签: postgresql recursion

我有一个类似于这个定义的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查询,它会更快吗?

1 个答案:

答案 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\'