MySQL/Postgres query 5 minutes interval data

common-table-expression, plpgsql, postgresql, recursive-query, sql

Solution

Recursive CTE

Since each row depends on the one before, it is hard to solve with a set-based approach. Resorting to a recursive CTE (which is standard 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
   )
   )
TABLE cte ORDER BY ts;

Aggregate functions are not allowed in a recursive CTE. I substituted with `ORDER BY` / `LIMIT 1`, which is fast when supported by an index on `ts`.

The parentheses around each leg of the `UNION` query are necessary to allow `LIMIT`, which would otherwise only be permitted once at the end of a `UNION` query.

PL/pgSQL function

A procedural solution (example with a plpgsql function) iterating through the sorted table would probably be a lot faster, since it can make do with a single table scan:

CREATE OR REPLACE FUNCTION f_rowgrid(i interval)
  RETURNS SETOF timestamp
  LANGUAGE plpgsql 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$;

Call:

SELECT * FROM  f_rowgrid('5 min');

db<>fiddle here - demonstrating both Old sqlfiddle

Here is a more complex example for this type of plpgsql functions:

- GROUP BY and aggregate sequential numeric values

Could easily be made generic with dynamic SQL and `EXECUTE` to work for arbitrary tables.

- There are quite a few code examples here on SO.

Problem

I need help with the query, let's say that this is the data in table. ``` 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 ``` I want to get every first row (timestamp) that is at least 5 minutes later than the last. In this case the query should return: ``` 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 ```

Original source

Related problems