PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

MySQL/Postgres fragt 5-Minuten-Intervalldaten ab

Rekursiver CTE

Da jede Zeile von der vorherigen abhängt, ist sie mit einem mengenbasierten Ansatz schwer zu lösen. Rückgriff auf einen rekursiven CTE (was Standard-SQL ist):

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;

Beachten Sie die Aktualisierung meines ersten Entwurfs:
Aggregatfunktionen sind in einem rekursiven CTE nicht zulässig. Ich habe durch ORDER BY ersetzt / LIMIT 1 , was schnell sein sollte, wenn es von einem Index unterstützt wird auf ts .

Die Klammern um jedes Bein der UNION Abfrage sind notwendig, um LIMIT zuzulassen , was sonst nur einmal am Ende einer UNION erlaubt wäre Abfrage.

PL/pgSQL-Funktion

Eine prozedurale Lösung (Beispiel mit einer plpgsql-Funktion), die durch die sortierte Tabelle iteriert, wäre wahrscheinlich viel schneller, da sie mit einem einzelnen Tabellenscan auskommt:

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;

Aufruf:

SELECT * FROM  f_rowgrid('5 min')

SQL-Fiddle demonstriert beides.

Hier ist ein etwas komplexeres Beispiel für diese Art von plpgsql-Funktion:

Könnte leicht mit dynamischem SQL und EXECUTE generisch gemacht werden um für beliebige Tabellen zu arbeiten.