如何从每2分钟存储的状态日志中确定事件的开始/结束时间

pao*_*785 1 mysql sql mariadb

MariaDB版本:版本:10.0.38-MariaDB-0 + deb8u1

我有一张表,其中每2分钟报告一次设备状态(开/关),其时间戳记为unix时间。

select * from devices_stats 
where device_id = 'LivingLight' 
  AND timestamp BETWEEN 1570080242 AND 1570084922;

+-------+-------------+--------+------------+-------------+
| id    | device_id   | status | timestamp  | device_iddr |
+-------+-------------+--------+------------+-------------+
| 16416 | LivingLight | OFF    | 1570080242 |           1 |
| 16427 | LivingLight | OFF    | 1570080363 |           1 |
| 16438 | LivingLight | OFF    | 1570080483 |           1 |
| 16449 | LivingLight | OFF    | 1570080602 |           1 |
| 16460 | LivingLight | OFF    | 1570080723 |           1 |
| 16471 | LivingLight | OFF    | 1570080842 |           1 |
| 16482 | LivingLight | ON     | 1570080963 |           1 |
| 16493 | LivingLight | ON     | 1570081083 |           1 |
| 16504 | LivingLight | ON     | 1570081203 |           1 |
| 16515 | LivingLight | ON     | 1570081323 |           1 |
| 16526 | LivingLight | ON     | 1570081443 |           1 |
| 16537 | LivingLight | ON     | 1570081563 |           1 |
| 16548 | LivingLight | ON     | 1570081682 |           1 |
| 16559 | LivingLight | ON     | 1570081803 |           1 |
| 16570 | LivingLight | ON     | 1570081922 |           1 |
| 16581 | LivingLight | ON     | 1570082042 |           1 |
| 16592 | LivingLight | ON     | 1570082163 |           1 |
| 16603 | LivingLight | ON     | 1570082283 |           1 |
| 16614 | LivingLight | ON     | 1570082402 |           1 |
| 16625 | LivingLight | ON     | 1570082523 |           1 |
| 16636 | LivingLight | ON     | 1570082643 |           1 |
| 16647 | LivingLight | ON     | 1570082762 |           1 |
| 16658 | LivingLight | ON     | 1570082882 |           1 |
| 16669 | LivingLight | OFF    | 1570083003 |           1 |
| 16680 | LivingLight | OFF    | 1570083123 |           1 |
| 16691 | LivingLight | OFF    | 1570083242 |           1 |
| 16702 | LivingLight | OFF    | 1570083363 |           1 |
| 16713 | LivingLight | OFF    | 1570083483 |           1 |
| 16724 | LivingLight | OFF    | 1570083603 |           1 |
| 16735 | LivingLight | OFF    | 1570083722 |           1 |
| 16746 | LivingLight | OFF    | 1570083843 |           1 |
| 16757 | LivingLight | OFF    | 1570083963 |           1 |
| 16768 | LivingLight | OFF    | 1570084083 |           1 |
| 16779 | LivingLight | OFF    | 1570084202 |           1 |
| 16790 | LivingLight | OFF    | 1570084323 |           1 |
| 16801 | LivingLight | OFF    | 1570084442 |           1 |
| 16812 | LivingLight | ON     | 1570084563 |           1 |
| 16823 | LivingLight | ON     | 1570084683 |           1 |
| 16834 | LivingLight | OFF    | 1570084803 |           1 |
| 16845 | LivingLight | OFF    | 1570084922 |           1 |
+-------+-------------+--------+------------+-------------+
Run Code Online (Sandbox Code Playgroud)

我想检索带有开始和结束时间的“ ON”事件的列表。

考虑到上面的例子,我想有这样的输出:

+-------------+------------+------------+
| device_id   | start      | stop       | 
+-------------+------------+------------+
| LivingLight | 1570080963 | 1570082882 |
| LivingLight | 1570084563 | 1570084683 |

Run Code Online (Sandbox Code Playgroud)

您能帮我创建查询吗?

Mad*_*iya 5

这是使用用户定义变量的方法。值得注意的是,即使Windowing函数也不能直接用于此问题。但是,您的版本很旧,也不支持它们。以下解决方案是通用的,如果不使用WHERE条件device_id并希望device_id在结果集中使用多个条件,则可以处理方案。

这里的总体思想是,我们chng为具有相同device_idstatus值(ON或OFF)的连续行(基于时间戳)计算一个“岛号”(在查询中表示)。最终,我们可以仅过滤出具有ON状态的那些岛,然后进行聚合以获得MIN()(开始时间戳)和MAX()(停止时间戳)。

模式(MySQL v5.7)

CREATE TABLE device_stats
    (`id` int, `device_id` varchar(11), `status` varchar(3), `timestamp` int, `device_iddr` int)
;

INSERT INTO device_stats
    (`id`, `device_id`, `status`, `timestamp`, `device_iddr`)
VALUES
    (16416, 'LivingLight', 'OFF', 1570080242, 1),
    (16427, 'LivingLight', 'OFF', 1570080363, 1),
    (16438, 'LivingLight', 'OFF', 1570080483, 1),
    (16449, 'LivingLight', 'OFF', 1570080602, 1),
    (16460, 'LivingLight', 'OFF', 1570080723, 1),
    (16471, 'LivingLight', 'OFF', 1570080842, 1),
    (16482, 'LivingLight', 'ON', 1570080963, 1),
    (16493, 'LivingLight', 'ON', 1570081083, 1),
    (16504, 'LivingLight', 'ON', 1570081203, 1),
    (16515, 'LivingLight', 'ON', 1570081323, 1),
    (16526, 'LivingLight', 'ON', 1570081443, 1),
    (16537, 'LivingLight', 'ON', 1570081563, 1),
    (16548, 'LivingLight', 'ON', 1570081682, 1),
    (16559, 'LivingLight', 'ON', 1570081803, 1),
    (16570, 'LivingLight', 'ON', 1570081922, 1),
    (16581, 'LivingLight', 'ON', 1570082042, 1),
    (16592, 'LivingLight', 'ON', 1570082163, 1),
    (16603, 'LivingLight', 'ON', 1570082283, 1),
    (16614, 'LivingLight', 'ON', 1570082402, 1),
    (16625, 'LivingLight', 'ON', 1570082523, 1),
    (16636, 'LivingLight', 'ON', 1570082643, 1),
    (16647, 'LivingLight', 'ON', 1570082762, 1),
    (16658, 'LivingLight', 'ON', 1570082882, 1),
    (16669, 'LivingLight', 'OFF', 1570083003, 1),
    (16680, 'LivingLight', 'OFF', 1570083123, 1),
    (16691, 'LivingLight', 'OFF', 1570083242, 1),
    (16702, 'LivingLight', 'OFF', 1570083363, 1),
    (16713, 'LivingLight', 'OFF', 1570083483, 1),
    (16724, 'LivingLight', 'OFF', 1570083603, 1),
    (16735, 'LivingLight', 'OFF', 1570083722, 1),
    (16746, 'LivingLight', 'OFF', 1570083843, 1),
    (16757, 'LivingLight', 'OFF', 1570083963, 1),
    (16768, 'LivingLight', 'OFF', 1570084083, 1),
    (16779, 'LivingLight', 'OFF', 1570084202, 1),
    (16790, 'LivingLight', 'OFF', 1570084323, 1),
    (16801, 'LivingLight', 'OFF', 1570084442, 1),
    (16812, 'LivingLight', 'ON', 1570084563, 1),
    (16823, 'LivingLight', 'ON', 1570084683, 1),
    (16834, 'LivingLight', 'OFF', 1570084803, 1),
    (16845, 'LivingLight', 'OFF', 1570084922, 1)
;
Run Code Online (Sandbox Code Playgroud)

查询#1

SELECT 
  device_id, MIN(timestamp) AS start, MAX(timestamp) AS stop 
FROM 
(
SELECT
  @c := IF(@s <> status OR @d <> device_id , @c+1, @c) AS chng, 
  @s := status AS status, 
  @d := device_id AS device_id, 
  timestamp
FROM 
(
  SELECT device_id, status, timestamp
  FROM device_stats 
  WHERE device_id = 'LivingLight' 
    AND timestamp BETWEEN 1570080242 AND 1570084922 
  ORDER BY device_id, timestamp
) t1
CROSS JOIN (SELECT @s := '', 
                   @d := '',
                   @c := 0) vars 
) t2 
WHERE t2.status = 'ON' 
GROUP BY device_id, chng;

| device_id   | start      | stop       |
| ----------- | ---------- | ---------- |
| LivingLight | 1570080963 | 1570082882 |
| LivingLight | 1570084563 | 1570084683 |
Run Code Online (Sandbox Code Playgroud)

在数据库小提琴上查看