CTE ricorsivo
Poiché ogni riga dipende da quella precedente, è difficile da risolvere con un approccio basato sugli insiemi. Ricorrere a un CTE ricorsivo (che è SQL standard):
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;
Nota l'aggiornamento dalla mia prima bozza:
Le funzioni aggregate non sono consentite in un CTE ricorsivo. Ho sostituito con ORDER BY
/ LIMIT 1
, che dovrebbe essere veloce se supportato da un indice su ts
.
Le parentesi attorno a ciascuna gamba di UNION
query sono necessarie per consentire LIMIT
, che altrimenti sarebbe consentito solo una volta alla fine di un UNION
interrogazione.
Funzione PL/pgSQL
Una soluzione procedurale (esempio con una funzione plpgsql) che itera attraverso la tabella ordinata sarebbe probabilmente molto più veloce, poiché può accontentarsi di una scansione di una singola tabella:
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;
Chiama:
SELECT * FROM f_rowgrid('5 min')
SQL Fiddle dimostrando entrambi.
Ecco un esempio un po' più complesso per questo tipo di funzione plpgsql:
Potrebbe essere facilmente reso generico con SQL dinamico e EXECUTE
per lavorare con tabelle arbitrarie.