代码之家  ›  专栏  ›  技术社区  ›  Artefacto

有向无环图:查找特定节点的所有路径

  •  3
  • Artefacto  · 技术社区  · 14 年前

    如何找到来自特定节点(示例中的节点36)的所有路径?

    假设我们有两张桌子:

    CATEGORIES      CATEG_PARENTS
    id              idc  | idparent
    --              ----------------
    1               2      1
    2               2      20
    5               5      2
    8               8      5
    20              20     1
    22              22     8
    30              22     20
    31              30     20
    36              31     22
                    31     30
                    36     31
    

    以下是两种可能的表述:

    alt text
    (来源: glopes at nebm.ist.utl.pt )

    alt text
    (来源: glopes at nebm.ist.utl.pt )

    这就是我想要的结果:

    ids
    -------------------
    "{1,20,22,31}"
    "{1,20,2,5,8,22,31}"
    "{1,20,30,31}"
    "{1,2,5,8,22,31}"
    

    (我会把我想出来的答案写下来,但如果有更简单的,我会接受)

    1 回复  |  直到 5 年前
        1
  •  4
  •   Artefacto    14 年前
    WITH RECURSIVE parent_line(path, id) AS (
        SELECT ARRAY[(row_number() OVER (PARTITION BY CP.idc))::integer], C.id
        FROM categorias C JOIN categ_parents CP ON C.id = CP.idparent
        WHERE CP.idc = 36
        UNION ALL
        SELECT PL.path || (row_number() OVER (PARTITION BY PL.id))::integer,
            C.id
        FROM categorias C
        JOIN categ_parents CP ON C.id = CP.idparent
        JOIN parent_line PL on CP.idc = PL.id
    ),
    real_parent_line(path, chainid, id) AS (
        SELECT PL.path, (row_number() OVER (PARTITION BY PL.id)),
            PL.id
        FROM parent_line PL
        WHERE PL.id IN (
            SELECT id
            FROM categorias C LEFT JOIN categ_parents CP
                ON (C.id = CP.idc)
            WHERE CP.idc IS NULL
        )
        UNION ALL
        SELECT PL.path, chainid, PL.id
        FROM parent_line PL, real_parent_line RPL
        WHERE array_upper(PL.path,1) + 1 = array_upper(RPL.path,1)
            AND PL.path = RPL.path[1:(array_upper(RPL.path,1)-1)]
    )
    SELECT array_accum(id) AS ids
    FROM real_parent_line RPL
    GROUP BY chainid;
    

    WITH 第条规定:

    path             | id
    ------------------------
    "{1}"              31
    "{1,1}"            22
    "{1,2}"            30
    "{1,1,1}"          20
    "{1,1,2}"          8
    "{1,2,1}"          20
    "{1,1,2,1}"        5
    "{1,1,1,1}"        1
    "{1,2,1,2}"        1
    "{1,1,2,1,1}"      2
    "{1,1,2,1,1,1}"    1
    "{1,1,2,1,1,2}"    20
    "{1,1,2,1,1,2,1}"  1
    

    感谢#postgresql@freenode 寻求帮助。