Совокупные прошедшие минуты на почасовой основе PostgreSQL - PullRequest
0 голосов
/ 01 апреля 2020

У меня есть столбец даты и времени. Мне нужно вывести столбец общих минут, прошедших от первого до последнего значения каждого часа, сгруппированных по часам, но в случае перекрывающегося события время должно быть распределено между двумя часами. Существует также условие, при котором, если прошедшее время между двумя последовательными записями превышает 30 минут, его следует игнорировать.

Ниже я объяснил три этапа: «Исходный», «Промежуточный» (вычисление промежуточного итога). ) и Финал.

enter image description here

И я планирую собирать почасовые инкрементальные данные для одного и того же, так как мы можем правильно объединить его с старые данные - это другой вопрос.

Пример данных:

 Moves_TS
1/4/2020 10:00
1/4/2020 10:25
1/4/2020 10:42
1/4/2020 10:56
1/4/2020 10:59
1/4/2020 11:02
1/4/2020 11:24
1/4/2020 11:43
1/4/2020 11:55
1/4/2020 12:26
1/4/2020 12:29

Промежуточный уровень:

Moves_TS    Hour    Running Total
1/4/2020 10:00  10  0
1/4/2020 10:25  10  25
1/4/2020 10:42  10  42
1/4/2020 10:56  10  56
1/4/2020 10:59  10  60
1/4/2020 11:02  11  2
1/4/2020 11:24  11  24
1/4/2020 11:43  11  43
1/4/2020 11:55  11  55
1/4/2020 12:26  12  0
1/4/2020 12:29  12  3

Окончательный результат:

Hour    Work done/Hour
10  60
11  55
12  3

Ответы [ 2 ]

1 голос
/ 01 апреля 2020

Это проблема пробелов и островков с некоторыми поворотами. Сначала я бы подвел итог «островам», определенным промежутками в 30 минут:

select min(moves_ts) as start_ts, max(moves_ts) as end_ts
from (select o.*,
             count(prev_moves_ts) filter (where moves_ts > prev_moves_ts + interval '30 minute') over (order by moves_ts) as grp
      from (select o.*, lag(moves_ts) over (order by moves_ts) as prev_moves_ts
            from original o
           ) o
     ) o
group by grp;

Затем вы можете использовать это с generate_series(), чтобы расширить данные и рассчитать перекрытия с каждым часом:

with islands as (
      select min(moves_ts) as start_ts, max(moves_ts) as end_ts
      from (select o.*,
                   count(prev_moves_ts) filter (where moves_ts > prev_moves_ts + interval '30 minute') over (order by moves_ts) as grp
            from (select o.*, lag(moves_ts) over (order by moves_ts) as prev_moves_ts
                  from original o
                 ) o
           ) o
      group by grp
     )
select hh.hh,
       sum( least(hh.hh + interval '1 hour', i.end_ts) -
            greatest(hh.hh, i.start_ts)
          ) as duration           
from (select generate_series(date_trunc('hour', min(moves_ts)),
                             date_trunc('hour', max(moves_ts)),
                             interval '1 hour'
                            ) hh
      from original o
     ) hh left join
     islands i
     on i.start_ts < hh.hh + interval '1 hour' and
        i.end_ts >= hh.hh
group by hh.hh
order by hh.hh;

Здесь - это дБ <> скрипка.

0 голосов
/ 01 апреля 2020
select 
   MOVES_TS, 
   Hour, 
   TO_CHAR(MOVES_TS,'YYYYMMDDHH') DATEHR,
   MIN(Moves_TS) over (partition by DATEHR) as MIN_MOVES_TS,
   (
    DATE_PART('day', MOVES_TS - MIN_MOVES_TS) * 24 +
   DATE_PART('hour', MOVES_TS - MIN_MOVES_TS) * 60 + 
   DATE_PART('minute', MOVES_TS - MIN_MOVES_TS)
   ) as RunningTotal

from dataset

...