Группировка по месяцу, дню, часу + пробелы и проблема островов - PullRequest
0 голосов
/ 13 ноября 2018

Мне нужно рассчитать (в процентах), как долго статус был истинным в течение дня, часов или месяца (working_time).

Я упрощаю свой стол до этого:

| date                      | status    |
|-------------------------- |--------   |
| 2018-11-05T19:04:21.125Z  | true      |
| 2018-11-05T19:04:22.125Z  | true      |
| 2018-11-05T19:04:23.125Z  | true      |
| 2018-11-05T19:04:24.125Z  | false     |
| 2018-11-05T19:04:25.125Z  | true      |
....

Мне нужно получить результат (зависит от параметра):

для часов:

| date                      | working_time |
|-------------------------- |--------------|
| 2018-11-05T00:00:00.000Z  | 14           |
| 2018-11-05T01:00:00.000Z  | 15           |
| 2018-11-05T02:00:00.000Z  | 32           |
|...                        | ...          |
| 2018-11-05T23:00:00.000Z  | 13           |

по месяцам:

| date                      | working_time |
|-------------------------- |--------------|
| 2018-01-01T00:00:00.000Z  | 14           |
| 2018-02-01T00:00:00.000Z  | 15           |
| 2018-03-01T00:00:00.000Z  | 32           |
|...                        | ...          |
| 2018-12-01T00:00:00.000Z  | 13           |

Мой SQL-запрос выглядит так:

 SELECT date_trunc('month', date)                                         as date,
       round((EXTRACT(epoch from sum(time_diff)) / 25920) :: numeric, 2) as working_time
FROM (SELECT date,
             status as current_status,
             (lag(status, 1) OVER (ORDER BY date)) AS previous_status,
             (date -(lag(date, 1) OVER (ORDER BY date))) AS time_diff
      FROM table
     ) as raw_data
WHERE current_status = TRUE AND previous_status = TRUE
GROUP BY date_trunc('month', date)
ORDER BY date;

и работает нормально, но очень медленно. Есть идеи по оптимизации? Можно ли использовать функцию Row_Number ()?

1 Ответ

0 голосов
/ 14 ноября 2018

Попробуйте это:

   SELECT t.month_reference as date,
            round(  sum(if(t_aux.status,1,0))  / 25920) :: numeric, 2) as working_time 

# Я полагаю, вы используете этот номер, потому что время работы системы 60 * 18 * 24,

# Я бы использовал это, если бы я хотелобщее количество секунд в месяце 60 * 60 * 24 * день (Last_day (t.month_reference))

FROM (SELECT date_trunc('month', t.date) as month_reference
          FROM table
         ) as t
    left join table t_aux
    on t.month_reference=date_trunc('month', t_aux.date) 

, поэтому, когда мы группируем по месяцам, sum () найдет только те строки, которые являются истинными и имеютуказанный месяц

   and t_aux.date < 
    (select t1.date 
    from table t1 
    where t.month_reference=date_trunc('month', t1.date) 
    and t1.status=false 
    order by t1.date asc limit 1 )

Я добавляю это, чтобы он выбирал только строки, которые являются истинными, пока не найдет строку со статусом false в том же месячном номере

    GROUP BY t.month_reference
    ORDER BY t.month_reference;
...