如何计算同一张表中datetime字段的行间时间差值?
看起来你需要计算同一个任务内相邻记录的时间差对吧?这在处理时序任务日志时很常见,我给你两种常见的解决方案,适配不同的数据库版本:
方案一:使用窗口函数(推荐,适用于MySQL 8.0+、PostgreSQL、SQL Server等)
现在主流数据库都支持窗口函数,用LAG()可以轻松获取上一行的时间值,再结合时间差函数计算即可:
SELECT task, status, stime, id, -- 计算与上一行的分钟差,可替换为HOUR/SECOND等单位 TIMESTAMPDIFF(MINUTE, LAG(stime) OVER (PARTITION BY task ORDER BY stime), stime) AS time_diff_minutes FROM tblwork;
代码解释:
PARTITION BY task:按任务分组,确保我们只计算同一个任务内的时间差ORDER BY stime:按触发时间排序,保证相邻行是时间先后顺序的记录LAG(stime):获取当前行在分组内的上一行的stime值TIMESTAMPDIFF(MINUTE, ...):计算两个时间的分钟差值,你可以根据需求替换单位
方案二:使用变量(适用于MySQL 5.x等不支持窗口函数的版本)
如果你的数据库版本比较旧,不支持窗口函数,可以用用户变量来跟踪上一行的任务和时间:
SELECT task, status, stime, id, TIMESTAMPDIFF(MINUTE, prev_stime, stime) AS time_diff_minutes FROM ( SELECT task, status, stime, id, -- 当任务不变时,用上一行的时间;任务变化时,设为NULL @prev_stime := CASE WHEN @current_task = task THEN @prev_stime ELSE NULL END AS prev_stime, -- 更新当前任务变量 @current_task := task FROM tblwork, (SELECT @current_task := '', @prev_stime := NULL) AS vars ORDER BY task, stime ) AS sub;
执行结果示例
无论用哪种方案,最终得到的结果都会类似这样(每个任务的第一条记录因为没有上一行,时间差为NULL):
| task | status | stime | id | time_diff_minutes |
|---|---|---|---|---|
| A | 1 | 2018-03-07 20:00:00 | 1 | NULL |
| A | 2 | 2018-03-07 20:30:00 | 2 | 30 |
| A | 1 | 2018-03-07 21:00:00 | 3 | 30 |
| A | 3 | 2018-03-07 21:30:00 | 4 | 30 |
| B | 1 | 2018-03-07 22:30:00 | 5 | NULL |
| B | 3 | 2018-03-07 23:30:00 | 6 | 60 |
如果想把NULL替换成0或者其他默认值,可以用COALESCE()函数包裹时间差计算部分,比如:
COALESCE(TIMESTAMPDIFF(MINUTE, LAG(stime) OVER (...), stime), 0) AS time_diff_minutes
内容的提问来源于stack exchange,提问作者Josef
相关产品推荐
相关产品推荐

