PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Soma da diferença de tempo entre as linhas


A dificuldade especial é não perder os intervalos de tempo para o período de tempo externo.
Supondo que a próxima linha para qualquer id sempre tem o status oposto.
Usando o nome da coluna ts em vez 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;

Retorna os intervalos conforme solicitado.
Os IDs sem entradas no intervalo de tempo selecionado não aparecem. Você teria que consultá-los adicionalmente.

SQL Fiddle.
Observação:eu lancei o resultado total_disconnected para text no violino, porque o tipo interval é exibido em um formato terrível.

Adicionar IDs sem entrada no período selecionado



Adicione à consulta acima (antes do ORDER BY 1 final ):
...
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.

Agora, apenas IDs sem entradas em ou antes o intervalo de tempo selecionado não aparece.