PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Somme des différences de temps entre les lignes

La difficulté particulière est de ne pas manquer les intervalles de temps jusqu'à la période extérieure.
En supposant que la ligne suivante pour un id donné a toujours le statut opposé.
Utilisation du nom de colonne ts au lieu de 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;

Renvoie les intervalles demandés.
Les ID sans entrée dans la plage de temps sélectionnée ne s'affichent pas. Vous auriez à les interroger en plus.

SQL Fiddle.
Remarque :je lance le résultat total_disconnected en text au violon, car le type interval est affiché dans un format terrible.

Ajouter des identifiants sans saisie dans la période sélectionnée


Ajouter à la requête ci-dessus (avant le dernier 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.

Désormais, seuls les identifiants sans entrées dans ou avant la plage horaire sélectionnée ne s'affiche pas.