您好我被困在这上面了。希望能够从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之间的时间差,并在设定的时间范围内将它们加在一起
答案 0 :(得分:0)
这是基本的想法......它将结果选择到row and
列, which you can then fetch with
PHP {...}
此解决方案假定停止&开始成对出现,即:开始的ID将是+1
停止的ID。否则,您应SELECT/JOIN
>
已停止ID的ID,LIMIT
到1
。
自连接可能不会产生最佳性能,因此请小心并测量执行时间,并确保一些数据安全。
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_downtime
是DateInterval
个对象。您可以使用format
方法返回消息:
echo $total_downtime->format('Total downtime: %h hours, %i minutes, %s seconds.');