Rekursiv CTE
Eftersom varje rad beror på den tidigare, är det svårt att lösa med ett set-baserat tillvägagångssätt. Tillgripa en rekursiv CTE (som är 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)
)
SELECT * FROM cte ORDER BY ts;
Notera uppdateringen från mitt första utkast:
Aggregerade funktioner är inte tillåtna i en rekursiv CTE. Jag ersatte med ORDER BY
/ LIMIT 1
, vilket bör vara snabbt när det stöds av ett index på ts
.
Parentesen runt varje ben i UNION
fråga är nödvändiga för att tillåta LIMIT
, som annars bara skulle vara tillåtet en gång i slutet av en UNION
fråga.
PL/pgSQL-funktion
En procedurlösning (exempel med en plpgsql-funktion) som itererar genom den sorterade tabellen skulle förmodligen vara mycket snabbare, eftersom den kan nöja sig med en enda tabellskanning:
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;
Ring:
SELECT * FROM f_rowgrid('5 min')
SQL Fiddle demonstrerar båda.
Här är ett något mer komplext exempel för denna typ av plpgsql-funktion:
Kan enkelt göras generisk med dynamisk SQL och EXECUTE
att arbeta för godtyckliga tabeller.