CTE Rekursif
Karena setiap baris bergantung pada baris sebelumnya, sulit untuk menyelesaikannya dengan pendekatan berbasis himpunan. Menggunakan CTE rekursif (yang merupakan SQL standar):
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;
Perhatikan pembaruan dari draf pertama saya:
Fungsi agregat tidak diizinkan dalam CTE rekursif. Saya ganti dengan ORDER BY
/ LIMIT 1
, yang seharusnya cepat bila didukung oleh indeks di ts
.
Tanda kurung di sekitar setiap kaki UNION
kueri diperlukan untuk mengizinkan LIMIT
, yang seharusnya hanya diizinkan sekali di akhir UNION
kueri.
Fungsi PL/pgSQL
Solusi prosedural (contoh dengan fungsi plpgsql) mengulangi tabel yang diurutkan mungkin akan jauh lebih cepat, karena dapat dilakukan dengan pemindaian tabel tunggal:
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;
Telepon:
SELECT * FROM f_rowgrid('5 min')
SQL Fiddle mendemonstrasikan keduanya.
Berikut adalah contoh yang agak lebih kompleks untuk jenis fungsi plpgsql ini:
Dapat dengan mudah dibuat generik dengan SQL dinamis dan EXECUTE
untuk bekerja untuk tabel arbitrer.