简体   繁体   English

行间时差

[英]Time difference between rows

In a mysql database (ver.5.7.15) I've got the following table named operation_list containing the following data: id ( autoincrement integer , primary key ), operation_date_time ( datetime ), operation ( enumerated values : START , STOP ), so the table looks like that:mysql数据库 (ver.5.7.15) 中,我有一个名为operation_list表,其中包含以下数据: id自动增量整数主键)、 operation_date_timedatetime )、操作枚举值STARTSTOP ),所以桌子看起来像这样:

+------+---------------------+-----------+
| id   | operation_date_time | operation |
+------+---------------------+-----------+
|    1 | 2000-01-01 06:30:45 | START     |
|    2 | 2000-01-01 07:45:00 | STOP      |
|    3 | 2000-01-01 08:18:12 | START     |
|    4 | 2000-01-01 11:23:58 | STOP      |
|    5 | 2000-01-01 15:45:01 | START     |
|    6 | 2000-01-01 19:01:33 | STOP      |
+------+---------------------+-----------+

Now, assuming that the first row is always a START, the last ROW is always a STOP, the STOP is always placed after a START, I need to retrieve the time difference between START and STOP in seconds.现在,假设第一行总是 START,最后一行总是 STOP,STOP 总是放在 START 之后,我需要以秒为单位检索 START 和 STOP 之间的时间差。 Hence, I need to write an SQL that would produce the following recordset:因此,我需要编写一个 SQL 来生成以下记录集:

+------+---------------------+-----------+
| id   | operation_date_time | duration  |
+------+---------------------+-----------+
|    1 | 2000-01-01 06:30:45 | 4455      |
|    3 | 2000-01-01 08:78:12 | 11146     |
|    5 | 2000-01-01 15:45:01 | 11792     |  
+------+---------------------+-----------+

Where 4455 is equivalent to 1 hour, 14 minutes and 15 seconds, 11146 is equivalent to 3 hours, 5 minutes and 46 seconds, 11792 is equivalent to 3 hours, 16 minutes and 32 seconds, and so on.其中4455相当于1小时14分15秒,11146相当于3小时5分46秒,11792相当于3小时16分32秒,以此类推。

What's the best way to do it in a single SQL statement without creating additional tables or dedicated scripting?在不创建附加表或专用脚本的情况下,在单个 SQL 语句中执行此操作的最佳方法是什么?

This works IN mysql 5.X这适用于 mysql 5.X

But it is uglier as in 8.0但它比 8.0 更丑

SELECT
   MIN(id) id
  ,MIN(`operation_date_time`) `operation_date_time`
  ,MAX(diff) duration  
FROM
(SELECT 
  id
  , IF(`operation` = 'START', 0,TIME_TO_SEC(TIMEDIFF(`operation_date_time`,  @datetime))) diff
  ,IF(`operation` = 'START',  @count := @count + 1,@count := @count) groupby
  ,@datetime := `operation_date_time` `operation_date_time`
 FROM
  (SELECT * FROM timetable ORDER by `operation_date_time` ASC) t1, (SELECT @datetime := NOW()) a,
   (SELECT @count := 0) b) t2
GROUP by groupby;
 CREATE TABLE timetable ( `id` INTEGER, `operation_date_time` VARCHAR(19), `operation` VARCHAR(5) ); INSERT INTO timetable (`id`, `operation_date_time`, `operation`) VALUES ('1', '2000-01-01 06:30:45', 'START'), ('2', '2000-01-01 07:45:00', 'STOP'), ('3', '2000-01-01 08:18:12', 'START'), ('4', '2000-01-01 11:23:58', 'STOP'), ('5', '2000-01-01 15:45:01', 'START'), ('6', '2000-01-01 19:01:33', 'STOP');
\n \n\n \n
SELECT MIN(id) id ,MIN(`operation_date_time`) `operation_date_time` ,MAX(diff) duration FROM (SELECT id , IF(`operation` = 'START', 0,TIME_TO_SEC(TIMEDIFF(`operation_date_time`, @datetime))) diff ,IF(`operation` = 'START', @count := @count + 1,@count := @count) groupby ,@datetime := `operation_date_time` `operation_date_time` FROM (SELECT * FROM timetable ORDER by `operation_date_time` ASC) t1, (SELECT @datetime := NOW()) a, (SELECT @count := 0) b) t2 GROUP by groupby;
\nid |身份证 | operation_date_time | operation_date_time | duration期间\n-: | -: | :------------------ | :------------------ | -------: -------:\n 1 | 1 | 2000-01-01 06:30:45 | 2000-01-01 06:30:45 | 4455 4455\n 3 | 3 | 2000-01-01 08:18:12 | 2000-01-01 08:18:12 | 11146 11146\n 5 | 5 | 2000-01-01 15:45:01 | 2000-01-01 15:45:01 | 11792 11792\n

db<>fiddle here db<> 在这里摆弄

Use window functions to get the ending time.使用窗口函数获取结束时间。 I am going to use a cumulative conditional min:我将使用累积条件最小值:

select t.*,
       timestampdiff(second, operation_date_time, stop_dt) as diff_seconds
from (select t.*,
             min(case when operation = 'STOP' then operation_date_time end) over (order by operation_date_time) as stop_dt
      from t
     ) t
where operation = 'START';

If the data really is interleaved, then you could just use lead() :如果数据确实是交错的,那么您可以使用lead()

select t.*,
       timestampdiff(second, operation_date_time, stop_dt) as diff_seconds
from (select t.*,
             lead(operation_date_time) over (order by operation_date_time) as stop_dt
      from t
     ) t
where operation = 'START';

EDIT:编辑:

In MySQL pre-8.0:在 MySQL 8.0 之前:

select t.*,
       timestampdiff(second, operation_date_time, stop_dt) as diff_seconds
from (select t.*,
             (select min(t2.operation_date_time)
              from t t2
              where t2.operation = 'STOP' and
                    t2.operation_date_time > t.operation_date_time
             ) as stop_dt
      from t
     ) t
where operation = 'START';

SELECT operation_date_time,DURATION FROM ( SELECT *,DATEDIFF(SECOND,operation_date_time,LEAD(operation_date_time)OVER(ORDER BY ID)) AS DURATION FROM PRACTICE )A WHERE operation='START'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM