Sql Postgres-多级父子关系数据

Sql Postgres-多级父子关系数据,sql,postgresql,performance,parent-child,hierarchical-data,Sql,Postgresql,Performance,Parent Child,Hierarchical Data,我们的亲子关系如下 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 va

我们的亲子关系如下

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);

生成表的脚本,如下所示

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);
我们希望根据下面提到的查询获取数据

  • 对于给定的包,获取可能的从属层次结构
  • 对于给定的包,获取父包列表
  • 如果我们需要维护这种父子关系(多对多),理想的模式结构应该是什么(记住性能)

  • 非常感谢您的帮助…愉快的编码…)

    这里是一个递归查询的快速示例,可以为每个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;
    
    以递归rcte为例(
    --递归种子
    选择packageid作为初始ID,
    包装,
    依亲包裹,
    将(packageid | |','| | dependent | u packageid转换为varchar(30))作为路径,
    1作为深度
    从依赖
    联合所有
    --递归项
    选择initialid,
    dependency.packageid,
    dependency.dependency_packageid,
    强制转换(rcte.path | |','| | dependency.dependent_packageid为varchar(30)),
    rcte深度+1
    来自rcte
    rcte.dependent_packageid上的内部联接依赖项=dependency.packageid
    )
    选择r1.initialid作为packageid,路径作为Dependent\u包
    来自rcte r1
    左外连接rcte r2
    在r2.path上,如r1.path | |“%”和r1.depth
    递归CTE有两部分。
    递归种子
    运行一次。它从表中收集记录,这些记录最初将被送入第二部分,即
    递归项
    ,该项将迭代直到其联接失败。在该递归术语中,我们将CTE
    rcte
    连接回表中,并将CTE的
    从属包ID
    连接到表的
    包ID

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


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

    我建议在表中添加主键:

    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
    

    您的模式适合于此。这里需要的是递归CTE。这是一个CTE内部的两部分查询,它会迭代地连接回自身,直到连接失败。
    SELECT dependant_packageid AS packageid, ARRAY_AGG(DISTINCT packageid)
    FROM dependency
    GROUP BY dependant_packageid
    ORDER BY dependant_packageid