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

Summe der Zeitdifferenz zwischen Zeilen

Die besondere Schwierigkeit besteht darin, die Zeitspannen zum äußeren Zeitrahmen nicht zu verpassen.
Angenommen, die nächste Zeile für eine beliebige id hat immer den gegenteiligen Status.
Mit dem Spaltennamen ts anstelle von recordTime :

WITH span AS (
   SELECT '2014-03-01 13:00'::timestamp AS s_from  -- start of time range
        , '2014-03-01 14:00'::timestamp AS s_to    -- end of time range
   )
, cte AS (
   SELECT id, ts, status, s_to
        , lead(ts, 1, s_from) OVER w AS span_start
        , first_value(ts)     OVER w AS last_ts
   FROM   span s
   JOIN   tbl  t ON t.ts BETWEEN s.s_from AND s.s_to
   WINDOW w AS (PARTITION BY id ORDER BY ts DESC)
   )
SELECT id, sum(time_disconnected)::text AS total_disconnected
FROM  (
   SELECT id, ts - span_start AS time_disconnected
   FROM   cte
   WHERE  status = 'Connected'

   UNION  ALL  
   SELECT id, s_to - ts
   FROM   cte
   WHERE  status = 'Disconnected'
   AND    ts = last_ts
   ) sub
GROUP  BY 1
ORDER  BY 1;

Gibt Intervalle wie angefordert zurück.
IDs ohne Einträge im ausgewählten Zeitraum werden nicht angezeigt. Diese müssten Sie zusätzlich abfragen.

SQL-Fiddle.
Hinweis:Ich übertrage das resultierende total_disconnected zu text in der Geige, weil der Typ interval wird in einem schrecklichen Format angezeigt.

IDs ohne Eingabe im ausgewählten Zeitraum hinzufügen


Zur Abfrage oben hinzufügen (vor dem letzten ORDER BY 1 ):

...
UNION  ALL
SELECT id, total_disconnected
   FROM  (
   SELECT DISTINCT ON (id)
          t.id, t.status, (s.s_to - s.s_from)::text AS total_disconnected
   FROM   span     s
   JOIN   tbl      t ON t.ts < s.s_from  -- only from before time range
   LEFT   JOIN cte c USING (id)
   WHERE  c.id IS NULL         -- not represented in selected time frame
   ORDER  BY t.id, t.ts DESC   -- only the latest entry
   ) sub
WHERE  status = 'Disconnected' -- only if disconnected
ORDER  BY 1;

SQL-Fiddle.

Jetzt nur IDs ohne Einträge in oder davor der ausgewählte Zeitraum wird nicht angezeigt.