用于获取存储在单个表中的 n 级父子关系的 Postgresql 查询

Posted

技术标签:

【中文标题】用于获取存储在单个表中的 n 级父子关系的 Postgresql 查询【英文标题】:Postgresql query for getting n-level parent-child relation stored in a single table 【发布时间】:2013-01-17 13:34:33 【问题描述】:

我有一个表示父子关系的表。关系可以深入到 n 级。

我使用以下查询创建了一个示例表:

CREATE SEQUENCE relations_rel_id_seq
    INCREMENT BY 1
    NO MAXVALUE
    NO MINVALUE
    CACHE 1;
CREATE TABLE relations(
    rel_id bigint DEFAULT nextval('relations_rel_id_seq'::regclass) NOT NULL PRIMARY KEY,
    rel_name text,
    rel_display text,
    rel_parent bigint
);

SQLFiddle

我需要查询表格并分层显示父子关系。我仍然不知道如何使用 sql 查询来查询 n 级深度。

对于 sqlfiddle,例如,预期的输出层次结构:

rel1
    rel11
        rel111
        rel112
            rel1121
rel2
    rel21
        rel211
        rel212

注意:n-level 中的 n 值未知。

数据库设计:

有没有更好的方法可以表达这种关系 方便查询的数据库?

【问题讨论】:

您可能正在寻找 WITH RECURSIVE,有一个示例 over here。 @muistooshort,感谢您的建议。会调查的。您对替代数据库设计有什么建议,在这种情况下可以更轻松地查询和检索关系? @saji89 阅读手册的this 页。它描述了您需要的WITH RECURSIVE 查询。 @saji89 BTW 很高兴提及您的 RDBMS 版本。递归查询在 8.4 以下的 PostgreSQL 中不可用。 我发现rel_parent 结构必须是最自然的树木设计;它是有道理的,并且在 WITH RECURSIVE 的情况下,对于所有常规操作都很容易使用。我想你可以看看“嵌套集”和“物化路径”。 【参考方案1】:

使用 Postgres,您可以使用递归公用表表达式:

with recursive rel_tree as (
   select rel_id, rel_name, rel_parent, 1 as level, array[rel_id] as path_info
   from relations 
   where rel_parent is null
   union all
   select c.rel_id, rpad(' ', p.level * 2) || c.rel_name, c.rel_parent, p.level + 1, p.path_info||c.rel_id
   from relations c
     join rel_tree p on c.rel_parent = p.rel_id
)
select rel_id, rel_name
from rel_tree
order by path_info;

基于您的示例的 SQLFiddle:http://sqlfiddle.com/#!11/59319/19

(我用下划线替换了缩进的空格,因为 SQLFiddle 不能正确显示空格)

【讨论】:

很好的答案,正是 OP 正在寻找的!但是rpad(..)部分有一点错误,改成rpad('', p.level * 2, ' ')。 SQL Fiddle 上的空格再次替换为“_”。 刚刚检查了docs:空格是默认填充字符(可选的第三个参数),所以我不得不在 SQLFiddle 上明确使用“_”填充字符。 +1,哇。 Postgresql 并没有停止让我感到惊讶。谢谢。 一时不知如何使用普通的with 表达式和with recursive。似乎您应该将 with 表达式放在 with recursive 中。 @mkataja:不,您只需添加它。 with recursive first_cte (...), second_cte (...) select * from second_cterecursive 关键字只需要 一次 以及初始的 with 关键字 - 无论哪个 CTE 是递归的。

以上是关于用于获取存储在单个表中的 n 级父子关系的 Postgresql 查询的主要内容,如果未能解决你的问题,请参考以下文章

查询获取同一张表中1:N关系的数据

使用 mongodb 聚合获取父子关系

沫沫金Sql查询树结构所有终极子节点

从同一表中获取具有级别的父子关系

Vue父子组件通信(父级向子级传递数据子级向父级传递数据Vue父子组件存储到data数据的访问)

如何从 Vapor 3 中的 JSON 响应中保存父子关系