MySQL - 找出连续日期时间之间的最大时间差

MySQL - Find the largest time difference between consecutive datetimes

我有一个包含日期时间列表的 table。

我想找到连续日期时间之间的最长时间量,即找到时间轴上彼此相邻的任意两个日期时间条目之间的最大距离。把它想象成“最长的连胜”——按时间顺序从一次重置到下一次重置的最长时间。

例如:

mysql> select * from resets order by datetime asc;
+----+---------------------+-------------+---------------------+---------------------+
| id | datetime            | activity_id | created_at          | updated_at          |
+----+---------------------+-------------+---------------------+---------------------+
|  7 | 2014-12-30 20:38:22 |           1 | 2015-01-06 20:38:22 | 2015-01-06 20:38:22 |
|  3 | 2014-12-31 20:38:22 |           1 | 2015-01-06 20:38:22 | 2015-01-06 20:38:22 |
|  5 | 2015-01-01 20:38:22 |           1 | 2015-01-06 20:38:22 | 2015-01-06 20:38:22 |
|  4 | 2015-01-02 20:38:22 |           1 | 2015-01-06 20:38:22 | 2015-01-06 20:38:22 |
|  6 | 2015-01-03 20:38:22 |           1 | 2015-01-06 20:38:22 | 2015-01-06 20:38:22 |
|  1 | 2015-01-04 20:38:22 |           1 | 2015-01-06 20:38:22 | 2015-01-06 20:38:22 |
|  2 | 2015-01-05 20:38:22 |           1 | 2015-01-06 20:38:22 | 2015-01-06 20:38:22 |

 etc...

从上面的示例数据集中,我想知道以下哪个时间差更大:

(很明显,它们都相隔正好 24 小时。我正在寻找一个通用的解决方案。)

这很容易用普通的编程语言完成,方法是遍历有序数组,存储连续值之间的差异,select取最大的一个。

是否有使用 SQL 的巧妙方法?

更新:

对我有用的查询是

SELECT MAX(DATEDIFF(r.next_datetime, r.datetime))
    FROM (

    # finds each datetime and the next consecutive one in the table
    SELECT r1.datetime as datetime, (

        # finds the next consecutive datetime
        SELECT datetime
        FROM resets r2
        WHERE r2.datetime > r1.datetime
        ORDER BY datetime ASC
        LIMIT 1
    ) as next_datetime

    FROM resets as r1
    ORDER BY r1.datetime

) as r;

最里面的查询 SELECT datetime FROM resets r2... 负责在列表中查找比当前日期时间大的下一个日期时间。请注意,此查询是有序的并且限制为 1。这对我来说是最困难的部分。

剩下的就很简单了。对于 table 中的每一行,我们 select 日期时间值和 table 中的下一个连续日期时间。最外层的查询找到我们刚刚创建的任何日期时间对之间的最大差异 - “连胜”。

我选择了@OllieJones 给出的答案,因为它是最简洁和最好的解释,即使我更喜欢“纯 SQL”解决方案。

您可以使用相关子查询计算下一个日期时间,然后通过排序找到最大的:

select r.*
from (select r.*,
             (select datetime
              from resets r2
              where r2.datetime > r.datetime
              order by datetime
              limit 1
             ) as next_datetime
      from resets r
     ) r
order by timestampdiff(second, datetime, next_datetime) desc
limit 1;

遗憾的是 MySQL 不支持 lag 获取上一行的日期时间,但您可以使用变量模拟它。

select max(timediff(datetime,prevDate)) from (
    select *, @prevDate prevDate, @prevDate := datetime
    from resets
    order by datetime 
) t1

或者如果您想要 select 整行

select * from (
    select *, @prevDate prevDate, @prevDate := datetime
    from resets
    order by datetime 
) t1 order by timediff(datetime,prevDate) desc limit 1

此查询将计算连续行之间的时间差并显示最大的一个 - 连胜的长度。如果您需要整行,则需要 Gordon 的查询。

SELECT MAX(diff)
  FROM (
          SELECT TIMEDIFF(datetime,@prev) AS diff,
                 (@prev:=datetime) AS datetime  
            FROM resets, 
                 (SELECT @prev:=(SELECT MIN(datetime) FROM resets)) AS init
           ORDER BY datetime
       ) AS diffs

这是如何工作的?

首先,它是单行查询和您的 table 之间的交叉连接。单行查询是这样的:

       (SELECT @prev:=(SELECT MIN(datetime) FROM resets)) 

将用户自定义值@prev设置为table中的lowest/earliestdatetime。这是在查询开始时初始化用户定义变量的 MySQL 技巧。

然后,SELECT 子句中有两列:

          SELECT TIMEDIFF(datetime,@prev) AS diff,
                 (@prev:=datetime) AS datetime  

第一个取当前行的 datetime@prev 的值之间的时间差。第二个将 @prev 的值更新为当前行的 datetime.

所以内部查询吐出时间戳列表以及与 ORDER BY datetime 中先前时间戳的差异。

外部查询 SELECT MAX(diff) 从内部查询中获取 diff 的最大值——最长连胜。

让我们明确一点:这是 MySQL 特有的猴子生意。纯 SQL 应该是声明性的,而不是程序性的。但是这个使用用户定义的 @prev 变量的技巧可以让我们以一种有用的方式混合声明式代码和过程式代码,即使它有些晦涩难懂。