【问题标题】:Postgres - multilevel parent child relation dataPostgres - 多级父子关系数据
【发布时间】:2019-11-27 14:08:18
【问题描述】:

我们有如下父子关系。

生成表格的脚本如下。

create table dependency ( packageid int, dependant_packageid int);
insert into dependency values (2,1);
insert into dependency values (3,1);
insert into dependency values (4,1);
insert into dependency values (5,2);
insert into dependency values (6,3);
insert into dependency values (7,4);
insert into dependency values (7,5);
insert into dependency values (8,5);
insert into dependency values (8,3);
insert into dependency values (4,5);
insert into dependency values (6,4);
insert into dependency values (5,3);

我们想根据下面提到的查询获取数据。

  1. 为给定的包获取可能的依赖层次结构

Ex:
packageid : 6
Result should be: [(3,1),(4,1),(4,5,2,1),(4,5,3,1)]
packageid : 7
Result should be: [(4,1),(4,5,2,1),(4,5,3,1)]
packageid : 8
Result should be: [(5,2,1),(5,3,1),(3,1)]
  1. 为给定包获取父包列表

Ex:
1 - 2,3,4
2 - 5
3 - 6,8,5
4 - 7,6
5 - 7,8,4
  1. 如果我们需要维护这种父子关系(多对多),理想的模式结构应该是什么(牢记性能)?

感谢任何帮助....愉快的编码....:)

【问题讨论】:

标签: sql postgresql performance parent-child hierarchical-data


【解决方案1】:

这是一个递归查询的快速快照,它为每个 id 吐出不同的完整依赖项列表:

WITH RECURSIVE rcte AS (
    --Recursive Seed
    SELECT packageid as initialid, 
        packageid,
        dependant_packageid, 
        CAST(packageid || ',' || dependant_packageid as varchar(30)) as path,
        1 as depth
    FROM dependency
    UNION ALL
    --Recursive Term
    SELECT initialid,
        dependency.packageid,
        dependency.dependant_packageid,
        CAST(rcte.path || ',' || dependency.dependant_packageid as varchar(30)),
        rcte.depth + 1
    FROM rcte
        INNER JOIN dependency ON rcte.dependant_packageid = dependency.packageid
)
SELECT r1.initialid as packageid, path as dependant_packages 
FROM rcte r1
    LEFT OUTER JOIN rcte r2
        ON r2.path LIKE r1.path || '%' AND r1.depth < r2.depth
WHERE r2.initialid IS NULL
ORDER BY r1.path;

递归 CTE 有两个部分。 recursive seed 运行一次。它从表中收集记录,这些记录最初将被送入第二部分,recursive term 将迭代直到其 JOIN 失败。在那个递归术语中,我们将 CTE rcte 连接回表,并将 CTE 的 dependant_packageid 连接到表的 packageid

最后,SELECT 语句引用了 CTE 的结果并自连接以从所有这些迭代中找到最长的不同路径。

使用相同的递归逻辑,您可以获得剩余的记录集。

【讨论】:

    【解决方案2】:

    我建议在您的表中添加一个主键:

    create table dependency (serial id, packageid int, dependant_packageid int);
    

    然后,要获取层次结构,您可以使用如下查询:

    WITH RECURSIVE rcte AS (
        SELECT id,
            packageid AS initial_packageid,
            dependant_packageid, 
            ARRAY[dependant_packageid::text]::text[] as path,
            1 as depth
        FROM dependency
        UNION ALL
        SELECT rcte.id,
            rcte.initial_packageid,
            dependency.dependant_packageid,
            rcte.path || dependency.dependant_packageid::text,
            rcte.depth + 1
        FROM rcte
            JOIN dependency ON rcte.dependant_packageid = dependency.packageid ),
        cte_hierarchy AS (
            SELECT initial_packageid AS packageid,
                (ARRAY_AGG( '(' || ARRAY_TO_STRING(path, ',') || ')' ORDER BY depth DESC))[1] AS hierarchy
            FROM rcte
            GROUP BY id, initial_packageid )
    SELECT packageid, STRING_AGG(hierarchy, ',')
    FROM cte_hierarchy
    GROUP BY packageid
    ORDER BY packageid
    

    要获取父包,只需使用:

    SELECT dependant_packageid AS packageid, ARRAY_AGG(DISTINCT packageid)
    FROM dependency
    GROUP BY dependant_packageid
    ORDER BY dependant_packageid
    

    【讨论】:

      猜你喜欢
      • 2010-10-05
      • 2020-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-19
      • 1970-01-01
      • 2012-08-07
      相关资源
      最近更新 更多