找出两个记录之间的时间

时间:2014-05-21 08:29:28

标签: mysql

所以这是我有一个表格,它记录了来自设备的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

5 个答案:

答案 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

SQLFiddle demo

答案 3 :(得分:0)

如果我理解得当,我认为你不能用一个查询来做。您需要一个存储过程。这是应该工作的步骤

  1. 创建存储过程
  2. 选择并循环表格数据
  3. 了解不断变化的状态和时间。让我们说当前行处于关闭状态,找出最接近状态并使用HOUR(TIMEDIFF(date1,date2))(IN MYSQL)找到时间差。所以现在状态变化之间存在时差
  4. 使用临时表来计算您的时间
  5. 我不太确定这是不是你想要的..尝试在存储过程中拧它..我认为它会起作用。

答案 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