MySQL/Postgres查询5分钟间隔数据

use*_*902 4 sql postgresql plpgsql recursive-query common-table-expression

我需要查询的帮助,让我们说这是表中的数据.

timestamp           
------------------- 
2010-11-16 10:30:00
2010-11-16 10:37:00
2010-11-16 10:40:00 
2010-11-16 10:45:00
2010-11-16 10:48:00
2010-11-16 10:55:00
2010-11-16 10:56:00
Run Code Online (Sandbox Code Playgroud)

我希望每个第一行(时间戳)比最后一行至少晚5分钟.在这种情况下,查询应返回:

timestamp           
------------------- 
2010-11-16 10:30:00
2010-11-16 10:37:00
2010-11-16 10:45:00
2010-11-16 10:55:00
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 5

递归CTE

由于每行依赖于前一行,因此很难用基于集合的方法解决.求助于递归CTE(标准SQL):

WITH RECURSIVE cte AS (
   (SELECT ts FROM tbl
    ORDER  BY ts
    LIMIT  1)

   UNION ALL
   (SELECT t.ts
    FROM   cte c
    JOIN   tbl t ON t.ts >= c.ts + interval '5 min'
    ORDER  BY t.ts
    LIMIT  1)
   )
SELECT * FROM cte ORDER BY ts;
Run Code Online (Sandbox Code Playgroud)

请注意我的第一稿中的更新:
递归CTE中不允许使用聚合函数.余取代有ORDER BY/ LIMIT 1,当由支撑这应该是快速索引上ts.

UNION查询的每个分支周围的括号是允许的LIMIT,否则只允许在UNION查询结束时使用一次.

PL/pgSQL函数

迭代遍历排序表的过程解决方案(带有plpgsql函数的示例)可能要快得多,因为它可以使用单个表扫描:

CREATE OR REPLACE FUNCTION f_rowgrid(i interval)
  RETURNS SETOF timestamp AS
$func$
DECLARE
   _this  timestamp;
   _last  timestamp := '-infinity';     -- init so that 1 row passes
BEGIN

FOR _this IN
    SELECT ts FROM tbl ORDER BY 1
LOOP
    IF _this >= _last + i THEN
       RETURN NEXT _this;
       _last := _this;
    END IF;
END LOOP;

END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

呼叫:

SELECT * FROM  f_rowgrid('5 min')
Run Code Online (Sandbox Code Playgroud)

SQL Fiddle演示两者.

对于这种类型的plpgsql函数,这是一个更复杂的示例:

可以通过动态SQL轻松实现通用,并EXECUTE适用于任意表.