Rekurzivní CTE
Vzhledem k tomu, že každý řádek závisí na předchozím, je obtížné jej vyřešit pomocí přístupu založeného na množinách. Použití rekurzivního CTE (což je standardní 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;
Všimněte si aktualizace z mého prvního návrhu:
Agregační funkce nejsou povoleny v rekurzivním CTE. Nahradil jsem výrazem ORDER BY
/ LIMIT 1
, který by měl být rychlý, když je podporován indexem na ts
.
Závorky kolem každé větve UNION
dotazu jsou nutné k povolení LIMIT
, což by jinak bylo povoleno pouze jednou na konci UNION
dotaz.
Funkce PL/pgSQL
Procedurální řešení (příklad s funkcí plpgsql) procházející setříděnou tabulkou by pravděpodobně bylo mnohem rychlejší, protože si vystačí s jedním prohledáním tabulky:
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;
Volejte:
SELECT * FROM f_rowgrid('5 min')
SQL Fiddle předvedení obojího.
Zde je poněkud složitější příklad pro tento typ funkce plpgsql:
Mohl by být snadno generován pomocí dynamického SQL a EXECUTE
pracovat pro libovolné tabulky.