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:
Could easily be made generic with dynamic SQL and EXECUTE to work for arbitrary tables.