【问题标题】:Time difference between rows行间时间差
【发布时间】:2020-02-24 16:35:31
【问题描述】:

mysql 数据库 (ver.5.7.15) 中,我有一个名为 operation_list 的表,其中包含以下数据:id (autoincrement整数主键),操作日期时间日期时间),操作枚举值START,STOP),所以表格如下所示:

+------+---------------------+-----------+
| 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      |
+------+---------------------+-----------+

现在,假设第一行始终是 START,最后一行始终是 STOP,STOP 始终放在 START 之后,我需要检索 START 和 STOP 之间的时间差(以秒为单位)。因此,我需要编写一个 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     |  
+------+---------------------+-----------+

其中 4455 相当于 1 小时 14 分 15 秒, 11146 相当于 3 小时 5 分 46 秒, 11792 相当于 3 小时 16 分 32 秒,以此类推。

在不创建额外表或专用脚本的情况下,在单个 SQL 语句中执行此操作的最佳方法是什么?

【问题讨论】:

  • 用您正在使用的数据库标记您的问题。

标签: mysql sql datetime


【解决方案1】:

这适用于 mysql 5.X

但它比 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');
✓ ✓
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;
编号 |操作日期时间 |期间 -: | :----------------- | --------: 1 | 2000-01-01 06:30:45 | 4455 3 | 2000-01-01 08:18:12 | 11146 5 | 2000-01-01 15:45:01 | 11792

db小提琴here

【讨论】:

  • 刚刚完成对目标表的测试,该表比示例中的结构复杂得多。它工作得很好,性能很好,这正是我想要的!谢谢!
【解决方案2】:

SELECT operation_date_time,DURATION FROM ( 从实践中选择 *,DATEDIFF(SECOND,operation_date_time,LEAD(operation_date_time)OVER(ORDER BY ID)) 作为持续时间 )一个 WHERE 操作='START'

【讨论】:

  • MySQL 5.7.15 版本不支持此类功能
  • @PowerEngineering 这就是为什么正确标记您的问题是获得正确答案的关键部分的原因。有人提供了 2 个对您毫无价值的解决方案。
  • @Eric 我在描述文本中添加了 MySQL 版本。 MySQL 的版本,据我了解,无法添加到标签中。
【解决方案3】:

使用窗口函数获取结束时间。我将使用累积条件最小值:

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';

如果数据真的是交错的,那么你可以使用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';

编辑:

在 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';

【讨论】:

  • 谢谢,但是使用这个语句我得到了关于“over”关键字的错误。我使用的是 MySQL 5.7.15 版。
猜你喜欢
  • 2014-04-02
  • 2018-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多