Rekursiv CTE
Da hver række afhænger af den før, er det svært at løse med en sæt-baseret tilgang. At ty til en rekursiv CTE (som er 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;
Bemærk opdateringen fra mit første udkast:
Aggregerede funktioner er ikke tilladt i en rekursiv CTE. Jeg erstattede med ORDER BY
/ LIMIT 1
, hvilket burde være hurtigt, når det understøttes af et indeks på ts
.
Parenteserne omkring hvert ben af UNION
forespørgsler er nødvendige for at tillade LIMIT
, som ellers kun ville være tilladt én gang i slutningen af en UNION
forespørgsel.
PL/pgSQL-funktion
En proceduremæssig løsning (eksempel med en plpgsql-funktion), der gentager den sorterede tabel, ville sandsynligvis være meget hurtigere, da den kan nøjes med en enkelt tabelscanning:
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 til:
SELECT * FROM f_rowgrid('5 min')
SQL Fiddle demonstrerer begge dele.
Her er et noget mere komplekst eksempel på denne type plpgsql-funktion:
Kan nemt gøres generisk med dynamisk SQL og EXECUTE
at arbejde for vilkårlige tabeller.