所以这是我有一个表格,它记录了来自设备的gps数据以及引擎状态(开启或关闭)。我需要知道发动机状态开启和关闭的时间。
vehicle_id | engine_status | time_stamp
1 | on |2014-05-21 07:30:02
2 | off |2014-05-21 07:40:02
1 | on |2014-05-21 07:50:02
1 | on |2014-05-21 08:00:02
1 | on |2014-05-21 08:10:02
2 | on |2014-05-21 08:20:02
1 | off |2014-05-21 08:30:02
1 | off |2014-05-21 08:40:02
2 | on |2014-05-21 08:50:02
1 | off |2014-05-21 09:00:02
2 | on |2014-05-21 09:10:02
1 | off |2014-05-21 09:10:06
1 | off |2014-05-21 09:30:02
2 | on |2014-05-21 09:30:02
1 | off |2014-05-21 09:35:02
2 | on |2014-05-21 09:39:02
1 | off |2014-05-21 09:40:02
1 | off |2014-05-21 09:45:02
2 | off |2014-05-21 09:50:02
1 | on |2014-05-21 09:55:02
1 | on |2014-05-21 09:56:02
2 | off |2014-05-21 09:58:02
1 | on |2014-05-21 09:59:02
1 | on |2014-05-21 09:59:02
1 | on |2014-05-21 10:10:02
2 | off |2014-05-21 09:30:02
答案 0 :(得分:4)
考虑以下内容......
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(vehicle_id INT NOT NULL
,engine_status VARCHAR(12) NOT NULL
,time_stamp TIMESTAMP NOT NULL
);
INSERT INTO my_table VALUES
(1,'on' ,'2014-05-21 07:30:02'),
(2,'off' ,'2014-05-21 07:40:02'),
(1,'on' ,'2014-05-21 07:50:02'),
(1,'on' ,'2014-05-21 08:00:02'),
(1,'on' ,'2014-05-21 08:10:02'),
(2,'on' ,'2014-05-21 08:20:02'),
(1,'off' ,'2014-05-21 08:30:02'),
(1,'off' ,'2014-05-21 08:40:02'),
(2,'on' ,'2014-05-21 08:50:02'),
(1,'off' ,'2014-05-21 09:00:02'),
(2,'on' ,'2014-05-21 09:10:02'),
(1,'off' ,'2014-05-21 09:10:06'),
(1,'off' ,'2014-05-21 09:30:02'),
(2,'on' ,'2014-05-21 09:30:02'),
(1,'off' ,'2014-05-21 09:35:02'),
(2,'on' ,'2014-05-21 09:39:02'),
(1,'off' ,'2014-05-21 09:40:02'),
(1,'off' ,'2014-05-21 09:45:02'),
(2,'off' ,'2014-05-21 09:50:02'),
(1,'on' ,'2014-05-21 09:55:02'),
(1,'on' ,'2014-05-21 09:56:02'),
(2,'off' ,'2014-05-21 09:58:02'),
(1,'on' ,'2014-05-21 09:59:02'),
(1,'on' ,'2014-05-21 09:59:02'),
(1,'on' ,'2014-05-21 10:10:02'),
(2,'off' ,'2014-05-21 09:30:02');
SELECT vehicle_id
, engine_status
, SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(end,start)))) total
FROM
(
SELECT a.vehicle_id
, a.engine_status
, a.time_stamp start
, MIN(c.time_stamp) end
FROM
( SELECT *
, CASE WHEN @prev= vehicle_id THEN @i:=@i+1 ELSE @i:=1 END rank
, @prev:=vehicle_id
FROM my_table
, ( SELECT @i:=1,@prev:='')x
ORDER
BY vehicle_id
, time_stamp
) a
LEFT
JOIN
( SELECT *
, CASE WHEN @prev= vehicle_id THEN @i:=@i+1 ELSE @i:=1 END rank
, @prev:=vehicle_id
FROM my_table
, ( SELECT @i:=1,@prev:='')x
ORDER
BY vehicle_id
, time_stamp
) b
ON b.vehicle_id = a.vehicle_id
AND b.engine_status = a.engine_status
AND b.rank = a.rank - 1
LEFT
JOIN
( SELECT *
, CASE WHEN @prev= vehicle_id THEN @i:=@i+1 ELSE @i:=1 END rank
, @prev:=vehicle_id
FROM my_table
, ( SELECT @i:=1,@prev:='')x
ORDER
BY vehicle_id
, time_stamp
) c
ON c.vehicle_id = a.vehicle_id
AND c.engine_status = a.engine_status
AND c.rank >= a.rank
LEFT
JOIN
( SELECT *
, CASE WHEN @prev= vehicle_id THEN @i:=@i+1 ELSE @i:=1 END rank
, @prev:=vehicle_id
FROM my_table
, ( SELECT @i:=1,@prev:='')x
ORDER
BY vehicle_id
, time_stamp
) d
ON d.vehicle_id = c.vehicle_id
AND d.engine_status = c.engine_status
AND d.rank = c.rank + 1
WHERE b.rank IS NULL
AND c.rank IS NOT NULL
AND d.rank IS NULL
GROUP
BY a.vehicle_id
, a.engine_status
, a.rank
) x
GROUP BY vehicle_id, engine_status;
+------------+---------------+----------+
| vehicle_id | engine_status | total |
+------------+---------------+----------+
| 1 | off | 01:15:00 |
| 1 | on | 00:55:00 |
| 2 | off | 00:08:00 |
| 2 | on | 01:10:00 |
+------------+---------------+----------+
答案 1 :(得分:3)
查询已更新
我juste完成了另一个查询,有更好的性能:
SELECT
vehicle_id,
engine_status,
SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(end, start)))) time
FROM (
SELECT
vehicle_id,
engine_status,
time_stamp AS start,
(
SELECT MIN(time_stamp)
FROM engine_statuses ends
WHERE ends.time_stamp > starts.time_stamp
AND ends.vehicle_id = starts.vehicle_id
AND ends.engine_status <> starts.engine_status
) AS end
FROM engine_statuses starts
GROUP BY vehicle_id, end
HAVING end IS NOT NULL
) t
GROUP BY vehicle_id, engine_status
<强>结果
+------------+---------------+----------+
| vehicle_id | engine_status | time |
+------------+---------------+----------+
| 1 | on | 01:00:00 |
| 1 | off | 01:25:00 |
| 2 | on | 01:30:00 |
| 2 | off | 00:49:00 |
+------------+---------------+----------+
答案 2 :(得分:1)
如果vehicle_id是聚合级别并且状态被保留到相同vehicle_id的下一条记录
SELECT vehicle_id, Last_Status AS engine_status
, SUM(Dur) / 60 AS 'total(Minutes)'
FROM (SELECT a.vehicle_id
, a.engine_status
, a.time_stamp
, @last_status := @status AS Last_Status
, @status := a.engine_status
, @last_time := @time
, @time := a.time_stamp
, TIME_TO_SEC(TIMEDIFF(a.time_stamp, @last_time)) AS Dur
FROM my_table a
WHERE vehicle_id = 1
ORDER BY time_stamp) AS D
WHERE Dur >= 0
GROUP BY vehicle_id, Last_Status
UNION ALL
SELECT vehicle_id, Last_Status AS engine_status
, SUM(Dur) / 60 AS 'total(Minutes)'
FROM (SELECT a.vehicle_id
, a.engine_status
, a.time_stamp
, @last_status := @status AS Last_Status
, @status := a.engine_status
, @last_time := @time
, @time := a.time_stamp
, TIME_TO_SEC(TIMEDIFF(a.time_stamp, @last_time)) AS Dur
FROM my_table a
WHERE vehicle_id = 2
ORDER BY time_stamp) AS D
WHERE Dur >= 0
GROUP BY vehicle_id, Last_Status
SQLFiddle它提供的值与草莓的值不同,但OP中没有任何可能由不同假设引起的词语
如果只有engine_status是聚合器
SELECT Last_Status AS engine_status
, SUM(Dur) / 60 AS 'total(Minutes)'
FROM (SELECT a.vehicle_id
, a.engine_status
, a.time_stamp
, @last_status := @status AS Last_Status
, @status := a.engine_status
, @last_time := @time
, @time := a.time_stamp
, TIME_TO_SEC(TIMEDIFF(a.time_stamp, @last_time)) AS Dur
FROM my_table a
ORDER BY time_stamp) AS D
WHERE Dur >= 0
GROUP BY Last_Status
答案 3 :(得分:0)
如果我理解得当,我认为你不能用一个查询来做。您需要一个存储过程。这是应该工作的步骤
我不太确定这是不是你想要的..尝试在存储过程中拧它..我认为它会起作用。
答案 4 :(得分:0)
以下查询计算具有engine_status ='on'的记录与其先前记录之间的时间。所有这些间隔按照vehicle_id求和(在DB2上测试)。“开启”记录后跟“关闭”记录之间的时间不计算在内。
select vehicle_id, sum(tt1.time_stamp - coalesce((select max(time_stamp)
from timetable tt2
where tt1.vehicle_id = tt2.vehicle_id
and tt2.time_stamp < tt1.time_stamp
),
time_stamp))
from timetable tt1
where engine_status = 'on'
group by vehicle_id