CTE récursif
Étant donné que chaque ligne dépend de la précédente, il est difficile de résoudre avec une approche basée sur les ensembles. Recourir à un CTE récursif (qui est du 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;
Notez la mise à jour de mon premier brouillon :
Les fonctions d'agrégation ne sont pas autorisées dans un CTE récursif. J'ai remplacé par ORDER BY
/ LIMIT 1
, qui devrait être rapide lorsqu'il est pris en charge par un index sur ts
.
Les parenthèses autour de chaque jambe de l'UNION
requête sont nécessaires pour autoriser LIMIT
, qui ne serait autrement autorisé qu'une seule fois à la fin d'un UNION
requête.
Fonction PL/pgSQL
Une solution procédurale (exemple avec une fonction plpgsql) itérant dans la table triée serait probablement beaucoup plus rapide, car elle peut se contenter d'un seul parcours de table :
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;
Appel :
SELECT * FROM f_rowgrid('5 min')
SQL Fiddle démontrant les deux.
Voici un exemple un peu plus complexe pour ce type de fonction plpgsql :
Pourrait facilement être rendu générique avec SQL dynamique et EXECUTE
pour travailler avec des tables arbitraires.