Рекурсивен CTE
Тъй като всеки ред зависи от предишния, е трудно да се реши с подход, базиран на множество. Прибягване до рекурсивен CTE (което е стандартен 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;
Обърнете внимание на актуализацията от първата ми чернова:
Агрегираните функции не са разрешени в рекурсивен CTE. Замених с ORDER BY
/ LIMIT 1
, което трябва да е бързо, когато се поддържа от индекс на ts
.
Скобите около всеки крак на UNION
заявка са необходими за разрешаване на LIMIT
, което иначе би било разрешено само веднъж в края на UNION
заявка.
PL/pgSQL функция
Процедурно решение (пример с функция plpgsql), итериращо през сортираната таблица, вероятно би било много по-бързо, тъй като може да се справи с едно сканиране на таблица:
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;
Обаждане:
SELECT * FROM f_rowgrid('5 min')
SQL Fiddle демонстрирайки и двете.
Ето един малко по-сложен пример за този тип plpgsql функция:
Може лесно да се направи общ с динамичен SQL и EXECUTE
за работа с произволни таблици.