【问题标题】:Postgres. How to get all the parents that meet the childs criteria?邮递员。如何获得所有符合孩子标准的父母?
【发布时间】:2018-04-01 17:44:41
【问题描述】:

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

我得到了类似这张桌子的东西:

表格数据

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

查询结果

我一直在思考这个问题:

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 个父级。 非常感谢。

【问题讨论】:

    标签: sql postgresql recursion


    【解决方案1】:

    您可以为此使用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 不是 Parent_ID)

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

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

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

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

    这会导致无限循环(循环),最坏的情况是它会在深度 20 个循环后停止 (1>5>7>1>5>7>1>5>7>1>5>7 >1>5>7>1>5>7>1>5)。还有其他方法可以停止循环,例如使用路径字段:WHERE a.path NOT LIKE '%' || a.parent_id || '%'

    如果您需要,您可以通过最终选择变得更有趣,但这将使您完成 95% 的目标。

    【讨论】:

    • 哇,真的很好的解释,我对此感到疯狂,我读了一点关于递归 CTE 的文章,真是太棒了!感谢您,完全节省了一天。我将查询调整到我的表并且很好:D
    • 太棒了!我很高兴它开箱即用。递归 CTE 肯定有一个学习曲线,但是一旦您了解它们,它们就会变得非常有意义,并且是工具箱的绝佳工具。
    猜你喜欢
    • 1970-01-01
    • 2019-10-14
    • 1970-01-01
    • 2019-06-10
    • 1970-01-01
    • 2016-12-24
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多