2

我已经开始使用循环 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)。所以查询应该总是找到第一次连接断开和第一次重新连接之间的时间。

我认为可行的一种方法是查找连接断开或断开的所有行,但我怎样才能找到这些行?还有比这更好的解决方案吗?

我真的不知道查询应该是什么样子,因此非常感谢您的帮助。

谢谢,问候拉西

4

3 回答 3

0

我不确定这是否有效(如果不只是评论)

它确实:仅当 id1小于当前 id 的行具有不同的状态(因此选择任何 perion 的第一个条目)时才选择行,并通过 >= 和相同的状态确定结束时间。

SELECT ou.id AS outerId, 
       ou.timeColumn AS currentRowTime,
       ou.status AS currentRowStatus,
      (  SELECT max(time)
         FROM statusTable
         WHERE time >= ou.timeColumn AND status = ou.status) AS endTime
FROM statusTable ou
WHERE ou.status != 
       (SELECT status
        FROM statusTable
        WHERE id = (ou.id -1))
于 2012-07-25T21:28:31.743 回答
0

我现在真的没有时间调整它以适应您的设置,但是我在网页上做几乎相同的事情来监控计算机何时关闭,何时重新打开,然后计算它的总时间......

我也不知道您是否可以访问 PHP,如果不能完全忽略这一点。如果你这样做,你也许可以适应这样的事情:

$lasttype="OFF";
$ontime=0;
$totalontime=0;

$query2 = " SELECT
  log_unixtime,
  status
FROM somefaketablename
ORDER BY
  log_unixtime asc
;";

$result2=mysql_query($query2);
while($row2=mysql_fetch_array($result2)){
  if($lasttype=="OFF" && $row2['status']=="ON"){
    $ontime = $row2['log_unixtime'];
  }elseif($lasttype=="ON" && $row2['status']=="OFF"){
    $thisblockontime=$row2['log_unixtime']-$ontime;
    $totalontime+=($thisblockontime);
  }
  $lasttype=$row2['status'];
}

基本上,您从表示计算机已关闭的假行开始,然后遍历每个真实行。

如果计算机已关闭但现在已打开,请设置一个变量以查看它何时打开,然后继续循环...

继续循环直到计算机打开,但现在关闭。发生这种情况时,从当前行的时间中减去之前存储的打开时间。这显示了那组“ON”的持续时间。

就像我说的那样,你必须非常适应它才能让它做你想做的事情,但是如果你用“连接上/下”替换“计算机开/关”,它本质上是相同的想法......

使这项工作有效的一件事是我将日期存储为整数,作为 unix 时间戳。因此,您可能必须转换日期,以便减法起作用。

于 2012-07-25T21:37:19.913 回答
0

这是一种方法。

首先按时间戳顺序获取状态行(内联视图别名为s)。然后在处理每一行时使用 MySQL 用户变量来保留前一行的值。

我们真正要寻找的是紧跟一系列“下降”状态的“上升”状态。当我们找到状态为“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.

注意:要了解此查询在做什么,请剥离最外层的查询,然后只运行别名为的内联视图的查询d(您可以添加s.time到选择列表中。)

此查询正在获取具有“向上”或“向下”状态的每一行。“技巧”是它仅在结束“下降”期间的行上分配“开始”和“结束”时间(标记下降时期)。(也就是说,第一行状态为“向上”,然后是状态为“向下”的行。)这是真正完成工作的地方,最外面的查询只是过滤掉这个结果集中的所有“额外”行(我们不需要。)

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

内联视图 aliased as 的目的s是获取按时间戳值排序的行,以便我们按顺序处理它们。内联视图别名 asi就在那里,因此我们可以在查询开始时初始化一些用户变量。

如果我们在 Oracle 或 SQL Server 上运行,我们可以使用“分析函数”或“排名函数”(分别命名为)。MySQL 不提供类似的东西,所以我们必须“自己动手” ”。

于 2012-07-25T22:00:38.660 回答