Postgres的。如何让所有满足孩子标准的父母?

时间:2017-10-20 14:14:04

标签: sql postgresql recursion

我有点疯狂寻找这个问题的解决方案:

我有这样的表格:

表数据

enter image description here

我想要一个查询来获取所有传递条件的元素和所有父母,我的意思是,这个结果:

查询结果

enter image description here

我一直在考虑这个问题:

SELECT a.* FROM table a 
    JOIN table b ON b.id = a.id
    WHERE a.id IN (SELECT DISTINCT c.parent_id FROM table c WHERE c.condition = TRUE)
    OR b.id IN (SELECT DISTINCT c.id FROM table c WHERE c.condition = TRUE); 

但我只能通过这种方法获得一个级别的差异,我的意思是,如果没有条件,我不能得到超过1个父级。 非常感谢你。

1 个答案:

答案 0 :(得分:4)

您可以使用recursive CTE

WITH RECURSIVE recCTE AS
(
    /*Get all the true children to seed the recursive query*/
    SELECT
        id,
        parent_id,
        condition as initial_condition,
        1 as depth,
        CAST(id as varchar(50)) as path
    FROM
        table a
    WHERE
        a.id NOT IN (SELECT DISTINCT parent_id from table)
        and a.condition = 'true'

    UNION ALL

    /*Recursive bit that refers back to itself. Find the parents*/
    SELECT
        b.id,
        b.parent_id,
        a.initial_condition,
        depth + 1 as depth,
        cast(path || '>' || b.id as varchar(50)) as path        

    FROM
        recCTE a
        INNER JOIN table b ON
            a.parent_id = b.id
    WHERE
        /*avoid going too deep in case of cycling*/
        depth <= 20
)
SELECT * FROM recCTE

递归CTE使用两部分:

  1. 递归种子:这是UNION查询的前半部分。在此,我们确定了所有的孩子(ID不是父母ID),这些孩子是&#34; True&#34;

  2. 递归术语:这是UNION查询的后半部分。它在FROM子句中引用自身(recCTE)并再次加入table;将recCTE.parent_id(先前的迭代parent_id)链接到表id。然后提取该迭代所需的所有信息。

  3. 我几乎总是跟踪递归深度(到达此记录需要多少次递归)和路径(从最底层的子节点开始,我们点击此层次结构的其他节点才能到达此记录)。

    我利用深度来确保我们不会在兔子洞口走得太远。如果您有以下记录:

    +----+-----------+
    | id | parent_id |
    +----+-----------+
    |  1 |         5 |
    |  5 |         7 |
    |  7 |         1 |
    +----+-----------+
    

    哪种情况会导致无限循环(循环),最糟糕的情况是它会在深度达到20个周期后停止(1> 5> 7> 1> 5> 7> 1> 5> 7> 1> 5> 7&gt; 7&gt; 1为卤素; 5个7个1→5大于7→1→5)。还有其他方法可以停止循环,例如使用路径字段:WHERE a.path NOT LIKE '%' || a.parent_id || '%'

    如果你需要的话,你可以在最后的选择中获得更多的一点,但这会让你获得95%的成绩。