【问题标题】:Recursive SELECT with stop condition in SQL?SQL中带有停止条件的递归SELECT?
【发布时间】:2017-02-14 03:59:38
【问题描述】:

我的名为 element 的表格如下所示:

 id | successor | important
----------------------------
  1 | NULL      | 0
  2 | 4         | 1
  3 | 5         | 0
  4 | 8         | 0
  5 | 6         | 1
  6 | 7         | 0
  7 | NULL      | 0
  8 | 10        | 1
  9 | 10        | 0
 10 | NULL      | 0

我从一个元素的 ID 开始。每个元素可能有也可能没有后续元素。因此,给定任何元素 ID,我可以从 0..n 个元素构建一个元素链,具体取决于其后继者和后继者,依此类推。

假设我的起始 ID 是 2。这会产生以下链:

2 -> 4 -> 8 -> 10

现在我想问这个问题:一个特定的元素链是否至少包含一个重要== 1的元素?

在伪代码中,无需不必要检查即可实现这一点的函数可能如下所示:

boolean chainIsImportant(element)
{
    if (element.important == 1) {
        return true;
    }

    if (element.successor != NULL) {
        return chainIsImportant(element.successor);
    }

    return false;
}

我想这可以通过WITH RECURSIVE 来实现,对吧?找到重要 == 1 的元素后,如何停止递归?

【问题讨论】:

    标签: sql postgresql recursion recursive-query


    【解决方案1】:
    CREATE TABLE booltree
            ( id INTEGER NOT NULL PRIMARY KEY
            , successor INTEGER REFERENCES booltree(id)
            , important Boolean NOT NULL
            );
    
    INSERT INTO booltree(id , successor , important) VALUES
      ( 1, NULL     , False)
      ,(2, 4        , True)
      ,(3, 5        , False)
      ,(4, 8        , False)
      ,(5, 6        , True)
      ,(6, 7        , False)
      ,(7, NULL     , False)
      ,(8, 10       , True)
      ,(9, 10       , False)
     ,(10, NULL     , False)
            ;
    
    -- SELECT * FROM booltree;
    
    WITH RECURSIVE rec AS (
            SELECT id, important
            FROM booltree
            WHERE successor IS NULL
            UNION ALL
            SELECT bt.id, GREATEST(rec.important, bt.important) AS important
            FROM booltree bt
            JOIN rec ON bt.successor = rec.id
            )
    SELECT id, important
    FROM rec
    ORDER BY important, id;
    

    结果:

    CREATE TABLE
    INSERT 0 10
     id | important 
    ----+-----------
      1 | f
      6 | f
      7 | f
      9 | f
     10 | f
      2 | t
      3 | t
      4 | t
      5 | t
      8 | t
    (10 rows)
    

    注意:恕我直言,一旦找到真正的重要性,就无法停止递归(基本上,因为在递归联合中不允许使用左连接) 但是,如果您正在寻找一个给定的 id(或一组),那么也许您可以将其用作开始条件,然后向上搜索树。

    【讨论】:

      【解决方案2】:

      这通常通过聚合有问题的列并在 CTE 的递归部分中的连接上添加条件来完成:

      with recursive all_elements as (
        select id, successor, important, array[important] as important_elements
        from elements
        where successor is null
        union all
        select c.id, c.successor, c.important, p.important_elements||c.important
        from elements c
           join all_elements p on c.successor = p.id
        where 1 <> all(p.important_elements)
      )
      select *
      from all_elements;
      

      请注意,条件是“翻转”的,因为 where 子句定义了应该包含的那些行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-07-24
        • 2013-10-28
        • 2015-08-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多