Recursieve CTE
Omdat elke rij afhangt van de vorige, is het moeilijk op te lossen met een set-gebaseerde benadering. Toevlucht nemen tot een recursieve CTE (wat standaard SQL is):
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;
Let op de update van mijn eerste concept:
Geaggregeerde functies zijn niet toegestaan in een recursieve CTE. Ik heb vervangen door ORDER BY
/ LIMIT 1
, wat snel zou moeten zijn als het wordt ondersteund door een index op ts
.
De haakjes rond elk been van de UNION
zoekopdracht zijn nodig om LIMIT
. toe te staan , die anders slechts één keer zou zijn toegestaan aan het einde van een UNION
vraag.
PL/pgSQL-functie
Een procedurele oplossing (bijvoorbeeld met een plpgsql-functie) die de gesorteerde tabel doorloopt, zou waarschijnlijk een stuk sneller zijn, aangezien het kan volstaan met een enkele tabelscan:
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;
Bel:
SELECT * FROM f_rowgrid('5 min')
SQL Fiddle beide demonstreren.
Hier is een wat complexer voorbeeld voor dit type plpgsql-functie:
Kan gemakkelijk generiek worden gemaakt met dynamische SQL en EXECUTE
om voor willekeurige tabellen te werken.