PHP mySQL行间时间

时间:2016-06-16 22:25:10

标签: php mysql

您好我被困在这上面了。希望能够从mySQL数据库中拉出2个开始/停止行之间的时间。我的表看起来像这样

fillercdown_ndx |  time                 | B3_4_5
1               |  2016-06-16 14:59:45  | 0
2               |  2016-06-16 15:03:11  | 1

基本上,当记录为0时,机器停止,当记录为1时,机器重新启动。我需要能够计算机器在特定时间(例如上午8点到下午5点)之间停机的时间。是否会在用户输入时使用PHP显示它,但不知道SQL命令。

任何人都知道找到这个的最佳方法吗?

创建表

CREATE TABLE `fillercdown` (
 `fillercdown_ndx` int(11) NOT NULL AUTO_INCREMENT,
 `time` datetime DEFAULT NULL,
 `B3_4_5` int(11) DEFAULT NULL,
 PRIMARY KEY (`fillercdown_ndx`),
 KEY `fillercdowntimendx` (`time`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1

更新:

将会有数百个"开始"并且"停止"条目。我的目标是在php中为用户提供一个小表格,要求他们提供一个时间范围,如上午8点到下午5点,然后能够计算机器所停留的所有时间"停止" (当B3_4_5为0时)。我似乎无法找出正确的SQL调用来获取每个0和1之间的时间差,并在设定的时间范围内将它们加在一起

2 个答案:

答案 0 :(得分:0)

这是基本的想法......它将结果选择到row and, which you can then fetch with PHP {...}

此解决方案假定停止&开始成对出现,即:开始的ID将是+1停止的ID。否则,您应SELECT/JOIN >已停止ID的ID,LIMIT1

自连接可能不会产生最佳性能,因此请小心并测量执行时间,并确保一些数据安全。

http://sqlfiddle.com/#!9/de72bf/1

CREATE TABLE fillercdown (
 `fillercdown_ndx` int(11)  NOT NULL AUTO_INCREMENT,
 `time` datetime DEFAULT NULL,
 `B3_4_5` int(11) DEFAULT NULL,
  PRIMARY KEY (`fillercdown_ndx`),
  KEY `fillercdowntimendx` (`time`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;

INSERT INTO fillercdown
  (`time`, `B3_4_5`)
VALUES
  ('2016-06-16 14:00:45', 0),
  ('2016-06-16 14:01:00', 1),
  ('2016-06-16 16:00:00', 0),
  ('2016-06-16 16:01:00', 1)
  ;

SELECT SUM(TIMEDIFF(g.`time`, f.`time`))
FROM   fillercdown f
INNER JOIN fillercdown g
    ON g.`fillercdown_ndx` = (f.`fillercdown_ndx` + 1)
   AND g.`B3_4_5` = 1
   AND TIME(g.`time`) BETWEEN '08:00:00' AND '17:00:00'
WHERE  f.`B3_4_5` = 0
   AND TIME(f.`time`) BETWEEN '08:00:00' AND '17:00:00'

如果您想要包含机器停止但尚未重新启动的时间,您可以执行以下操作:

http://sqlfiddle.com/#!9/d113b9/9

INSERT INTO fillercdown
  (`time`, `B3_4_5`)
VALUES
  ('2016-06-16 14:00:45', 0),
  ('2016-06-16 14:01:00', 1),
  ('2016-06-16 16:00:00', 0),
  ('2016-06-16 16:01:00', 1),
  ('2016-06-16 16:02:00', 0)
  ;

SELECT  SUM(TIMEDIFF(COALESCE(g.`time`, '2016-06-16 16:02:01'), f.`time`))
FROM    fillercdown f
LEFT JOIN fillercdown g
ON g.`fillercdown_ndx` = (f.`fillercdown_ndx` + 1)
   AND g.`B3_4_5` = 1
   AND TIME(g.`time`) BETWEEN '08:00:00' AND '17:00:00'
WHERE   TIME(f.`time`) BETWEEN '08:00:00' AND '17:00:00' AND f.`B3_4_5` = 0

您可以将2016-06-16 16:02:01替换为NOW()或基于f.time的内容,当然这取决于您的应用需求。

如果您不想获得NULL而是0,如果没有匹配的行,请执行以下操作:COALESCE(SUM(...), 0)

如果您更喜欢脚本化解决方案,您可以随时执行以下操作:

SELECT  f.`time`, f.`B3_4_5`
FROM    fillercdown f
WHERE   TIME(f.`time`) BETWEEN '08:00:00' AND '17:00:00'

然后计算总和,就像这样(伪代码):

stopped = null;
pairs = []
for ( row in rows )
    if ( row.isStopped ) stopped = row
    else
        pairs += [stopped, row]
        stopped = null

sum = 0
for ( pair in pairs )
    sum += duration( pair[0], pair[1] )

答案 1 :(得分:0)

这就是我目前用来做同样的事情,听起来像你正在尝试做的事情。我使用的是PDO,如果你需要使用它,这可以很容易地适应mysqli。这取决于按时间交替关闭/开启值。如果由于某种原因有任何连续的off或on行,则预期的结果会变得不明确。

// First select everything in the requested range ordered by time.
$sql = "SELECT `time`, B3_4_5 FROM your_table WHERE `time` BETWEEN ? AND  ? ORDER BY `time`";
$stmt = $pdo->prepare($sql);
$stmt->execute([$query_start, $query_end]);

// Initialize two DateTime objects (start and end) used to calculate the total time.
$total_start = new DateTime('00:00');
$total_end = clone $total_start; 

$off = null;
while ($row = $stmt->fetchObject()) {
    if ($row->B3_4_5) {
        $on = new DateTime($row->time);
        // increment total end time with difference between current off/on times
        if ($off) {
            $total_end->add($on->diff($off));
        }
    } else {
        $off = new DateTime($row->time);
    }
}

// total downtime is difference between start and end DateTimes
$total_downtime = $total_start->diff($total_end);

$total_downtimeDateInterval个对象。您可以使用format方法返回消息:

echo $total_downtime->format('Total downtime: %h hours, %i minutes, %s seconds.');