我已经开始使用循环PHP脚本监视ISP的停机时间,该脚本每5秒自动检查一次连接并将结果存储在MySQL数据库中。脚本检查它是否能够访问几个远程网站并记录结果。检查的时间和状态始终存储在数据库中。
该表的结构如下:
id (auto increment) time (time stamp) status (varchar)
现在到我的问题。
我有数据,但是我不知道如何使用它来达到我想要的结果。基本上,我想查找连接断开的所有时间段以及连接断开的时间。
例如,如果我们有10行包含以下数据
0 | 2012-07-24 22:23:00 | up 1 | 2012-07-24 22:23:05 | up 2 | 2012-07-24 22:23:10 | down 3 | 2012-07-24 22:23:16 | down 4 | 2012-07-24 22:23:21 | up 5 | 2012-07-24 22:23:26 | down 6 | 2012-07-24 22:23:32 | down 7 | 2012-07-24 22:23:37 | up 8 | 2012-07-24 22:23:42 | up 9 | 2012-07-24 22:23:47 | up
查询应返回句点(从22:23:10到22:23:21,以及从22:23:26到22:23:37)。因此,查询应始终查找到第一次连接断开与第一次连接断开之间的时间。
我认为可行的一种方法是查找连接断开或上升的所有行,但是如何找到这些行呢?还有没有比这更好的解决方案了?
我真的不知道查询应该是什么样子,因此将不胜感激帮助。
谢谢,谢谢拉西
这是一种方法。
首先按时间戳顺序获取状态行(内联视图别名为s)。然后,在处理每一行时,请使用MySQL用户变量保留前几行的值。
s
我们真正要寻找的是紧随一系列“下降”状态之后的“上升”状态。当我们发现该行的状态为“ up”时,我们真正需要的是前一系列“ down”状态中的最早时间戳。
因此,类似这样的方法将起作用:
SELECT d.start_down , d.ended_down FROM (SELECT @i := @i + 1 AS i , @start := IF(s.status = 'down' AND (@status = 'up' OR @i = 1), s.time, @start) AS start_down , @ended := IF(s.status = 'up' AND @status = 'down', s.time, NULL) AS ended_down , @status := s.status FROM (SELECT t.time , t.status FROM mydata t WHERE t.status IN ('up','down') ORDER BY t.time ASC, t.status ASC ) s JOIN (SELECT @i := 0, @status := 'up', @ended := NULL, @start := NULL) i ) d WHERE d.start_down IS NOT NULL AND d.ended_down IS NOT NULL
这适用于您显示的特定数据集。
这不能处理的(不返回的内容)是尚未结束的“下降”时间段,即一系列“下降”状态,后面没有“上升”状态。
为避免文件排序操作按顺序返回行,您需要在上包含覆盖索引(time,status)。该查询将生成一个临时(MyISAM)表,以实现别名为的内联视图d。
(time,status)
d
注意: 要了解此查询的功能,请剥离该最外面的查询,然后仅对别名为的内联视图运行查询d(可以将其添加s.time到选择列表中。)
s.time
该查询使每一行都具有“ up”或“ down”状态。“技巧”是它仅在结束“下降”时间段的行上分配“开始”和“结束”时间(标记下降时间)。(也就是说,第一行的状态为“ up”,紧随其后的状态为“ down”。)这是完成实际工作的地方,最外面的查询只是过滤掉该结果集中的所有“多余”行(不需要。)
SELECT @i := @i + 1 AS i , @start := IF(s.status = 'down' AND (@status = 'up' OR @i = 1), s.time, @start) AS start_down , @ended := IF(s.status = 'up' AND @status = 'down', s.time, NULL) AS ended_down , @status := s.status , s.time FROM (SELECT t.time , t.status FROM mydata t WHERE t.status IN ('up','down') ORDER BY t.time ASC, t.status ASC ) s JOIN (SELECT @i := 0, @status := 'up', @ended := NULL, @start := NULL) i
内联视图别名的目的s是按时间戳值对行进行排序,因此我们可以按顺序处理它们。内联视图的别名i就在那里,因此我们可以在查询开始时初始化一些用户变量。
i
如果我们在Oracle或SQL Server上运行,则可以使用“解析函数”或“排名函数”(分别命名)。MySQL不提供类似的功能,因此我们必须“自行滚动” ”。