寻找递归查询的简单替代方法

时间:2016-04-07 23:06:30

标签: postgresql common-table-expression recursive-query

实际查询涉及更多,但我面临的问题可以归结为:

用于过滤单调递增整数的行集的查询,以便 - 最终结果集中的,行(n + 1).value> = row(n).value + 5

对于我需要解决的实际问题,行集计数在1000s内。

澄清一些例子:

  • 如果行为:1,2,3,4,5:则查询应返回:1
  • 如果行是:1,5,7,10,11,12,13:那么查询应返回:1,7,12
  • 如果行是:6,8,11,16,20,23:那么查询应返回:6,11,16,23
  • 如果行为:6,8,12,16,20,23:则查询应返回:6,12,20

我已经设法通过以下查询获得所需的结果,但它似乎过于复杂。取消注释不同的“..with t(k)..”以试用它们。

我正在寻找任何简化或替代方法来获得相同的结果。

    with recursive r(n, pri) as (
    with t(k) as (values (1),(2),(3),(4),(5))   -- the data we want to filter
    -- with t(k) as (values (1),(5),(7),(10),(11),(12),(13))
    -- with t(k) as (values (6),(8),(11),(16),(20),(23))
    -- with t(k) as (values (6),(8),(12),(16),(20),(23))
    select min(k), 1::bigint from t             -- bootstrap for recursive processing. 1 here represents rank().
    UNION
    select k, (rank() over(order by k)) rr      -- rank() is required just to filter out the rows we dont want from the final result set, and no other reason
    from r, t 
    where t.k >= r.n+5 and r.pri = 1            -- capture the rows we want, AND unfortunately a bunch of rows we dont want 
)
select n from r where pri = 1;                  -- filter out the rows we dont want

2 个答案:

答案 0 :(得分:0)

使用plpgsql怎么样?

drop table if exists t;
create table t(k) as (
  values 
    (1),(2),(3),(4),(5)
    --(1),(5),(7),(10),(11),(12),(13)
    --(6),(8),(11),(16),(20),(23)
    --(6),(8),(12),(16),(20),(23)
);

create or replace function foo(in n int, out k int) returns setof int as $$
declare
  r t;
  rp t;
begin
  rp := null;
  for r in (select * from t) loop
    if (rp is null) or (r.k >= rp.k + n) then
      rp := r;
      k := r.k;
      return next;
    end if;
  end loop;
  return;
end; $$ immutable language plpgsql;

select * from foo(5);

答案 1 :(得分:0)

-- The data:
CREATE TABLE rowseq(val INTEGER NOT NULL) ;
INSERT INTO rowseq(val ) values
    -- (1),(2),(3),(4),(5)
         (1), (5), (7), (10), (11), (12), (13)
    --(6),(8),(11),(16),(20),(23)
    --(6),(8),(12),(16),(20),(23)
        ;

        -- need this view, because a recursive CTE cannot be based on a CTE
        -- [we could also duplicate the row_number() in both legs of the recursive CTE]
CREATE TEMP VIEW qqq AS
        SELECT val, row_number() OVER (ORDER BY val) AS rn
        FROM rowseq
        ;

WITH RECURSIVE rrr AS (
        SELECT qqq.val, qqq.rn
        FROM qqq
        WHERE qqq.rn = 1
UNION
        SELECT q1.val, q1.rn
        FROM rrr
        JOIN qqq q1 ON q1.rn > rrr.rn AND q1.val >= rrr.val+5 -- The "Gap" condition
                AND NOT EXISTS ( SELECT * FROM  qqq nx                  -- But it must be the FISRT match
                        WHERE nx.rn > rrr.rn AND nx.val >= rrr.val+5    -- same condition
                        AND nx.rn < q1.rn                               -- but NO earlier match
                        )
        )
-- prove it to the world!
SELECT *
FROM rrr
        ;