MySQL вопрос по созданию отчета по событиям

Есть таблица events с двумя столбцами: datetime (дата и время события) и type (тип события). В таблицу записываются два типа событий - события включения и события выключения прибора. Требуется посчитать, сколько часов был включен прибор за период времени.


Ответы (2 шт):

Автор решения: Oopss

Если вкл выкл не последовательно, проверки нет, работать не будет. Временная таблица необязательно, только для наглядности.

-- create
CREATE TABLE events (
  ev_datetime datetime PRIMARY KEY,
  ev_type int NOT NULL
  
);

-- insert
INSERT INTO events(ev_type, ev_datetime) values
(1,'2024-02-27 00:54:00'),
(0,'2024-02-27 01:28:00'),
(1,'2024-02-27 02:19:00'),
(0,'2024-02-27 03:13:00'),
(1,'2024-02-27 03:38:00'),
(0,'2024-02-27 03:56:00'),
(1,'2024-02-27 04:48:00'),
(0,'2024-02-27 05:28:00'),
(1,'2024-02-27 06:17:00'),
(0,'2024-02-27 07:06:00'),
(1,'2024-02-27 07:08:00'),
(0,'2024-02-27 07:29:00'),
(1,'2024-02-27 08:01:00'),
(0,'2024-02-27 08:36:00'),
(1,'2024-02-27 09:22:00'),
(0,'2024-02-27 09:25:00'),
(1,'2024-02-27 09:40:00'),
(0,'2024-02-27 10:04:00'),
(1,'2024-02-27 10:15:00'),
(0,'2024-02-27 10:26:00');

SELECT * FROM events;

CREATE TEMPORARY TABLE `tmp_table`
SELECT     t1.ev_datetime AS start_time,
           MIN(t2.ev_datetime) AS end_time,
           TIMESTAMPDIFF(MINUTE,t1.ev_datetime, MIN(t2.ev_datetime) ) AS delta_time
FROM events t1   JOIN events t2 ON t1.ev_datetime < t2.ev_datetime
WHERE t1.ev_type = 1 AND t2.ev_type = 0
     
   group by t1.ev_datetime;
   
SELECT * FROM tmp_table;
   
SELECT sum(delta_time) 
FROM  tmp_table
WHERE start_time>'2024-02-27 03:13:00' and start_time<' 2024-02-27 04:48:00';

Output:

+---------------------+---------+
| ev_datetime         | ev_type |
+---------------------+---------+
| 2024-02-27 00:54:00 |       1 |
| 2024-02-27 01:28:00 |       0 |
| 2024-02-27 02:19:00 |       1 |
| 2024-02-27 03:13:00 |       0 |
| 2024-02-27 03:38:00 |       1 |
| 2024-02-27 03:56:00 |       0 |
| 2024-02-27 04:48:00 |       1 |
| 2024-02-27 05:28:00 |       0 |
| 2024-02-27 06:17:00 |       1 |
| 2024-02-27 07:06:00 |       0 |
| 2024-02-27 07:08:00 |       1 |
| 2024-02-27 07:29:00 |       0 |
| 2024-02-27 08:01:00 |       1 |
| 2024-02-27 08:36:00 |       0 |
| 2024-02-27 09:22:00 |       1 |
| 2024-02-27 09:25:00 |       0 |
| 2024-02-27 09:40:00 |       1 |
| 2024-02-27 10:04:00 |       0 |
| 2024-02-27 10:15:00 |       1 |
| 2024-02-27 10:26:00 |       0 |
+---------------------+---------+
+---------------------+---------------------+------------+
| start_time          | end_time            | delta_time |
+---------------------+---------------------+------------+
| 2024-02-27 00:54:00 | 2024-02-27 01:28:00 |         34 |
| 2024-02-27 02:19:00 | 2024-02-27 03:13:00 |         54 |
| 2024-02-27 03:38:00 | 2024-02-27 03:56:00 |         18 |
| 2024-02-27 04:48:00 | 2024-02-27 05:28:00 |         40 |
| 2024-02-27 06:17:00 | 2024-02-27 07:06:00 |         49 |
| 2024-02-27 07:08:00 | 2024-02-27 07:29:00 |         21 |
| 2024-02-27 08:01:00 | 2024-02-27 08:36:00 |         35 |
| 2024-02-27 09:22:00 | 2024-02-27 09:25:00 |          3 |
| 2024-02-27 09:40:00 | 2024-02-27 10:04:00 |         24 |
| 2024-02-27 10:15:00 | 2024-02-27 10:26:00 |         11 |
+---------------------+---------------------+------------+
+-----------------+
| sum(delta_time) |
+-----------------+
|              18 |
+-----------------+
created 22 hours ago
MySQL online editor
→ Ссылка
Автор решения: ValNik

Считаем, что если произошло событие любого типа оно длится до следующего события (строки в таблице).
Поэтому нам нужно знать только тип и время (длительность) до следующего события. События каждого типа сложить отдельно.

При этом две или более подряд идущих строк одного типа нас вовсе не смущают.

Пример

select 
   sum(case when event_type=1 then elong end) Type1Long
  ,sum(case when event_type=0 then elong end) Type0Long
from(
select *
  ,time_to_sec(timediff(lead(event_time,1,event_time)over(order by event_time)
                       ,event_time))elong
from events
)x
where event_time between '2024-26-01 00:00:00' and '2024-03-28 23:59:59'

Или вариант для более ранних версий MySQL

select 
   sum(case when event_type=1 then elong end) Type1Long
  ,sum(case when event_type=0 then elong end) Type0Long
from(
select *
  ,time_to_sec(timediff((select min(event_time) from events e2 where e2.event_time>e.event_time )
          ,event_time))elong
from events e
)x
where event_time between '2024-26-01 00:00:00' and '2024-03-28 23:59:59'

Выход

Type1Long Type0Long
780 39240

Для данных

id event_time event_type elong
1 2024-02-28 14:12:00 1 180
2 2024-02-28 14:15:00 0 180
3 2024-02-28 14:18:00 1 240
4 2024-02-28 14:22:00 0 180
8 2024-02-28 14:25:00 0 120
5 2024-02-28 14:27:00 1 120
6 2024-02-28 14:29:00 1 240
7 2024-02-28 14:33:00 0 33960
9 2024-02-28 23:59:00 0 4800
10 2024-02-29 01:19:00 0 0
→ Ссылка