带有 UNIX 时间戳的 MySQL 表 - 按时间戳排序并计算一行与前一行之间的差异

Posted

技术标签:

【中文标题】带有 UNIX 时间戳的 MySQL 表 - 按时间戳排序并计算一行与前一行之间的差异【英文标题】:MySQL Table With UNIX Timestamps - Sorting By Timestamp And Calculating Difference Between One Row And Previous 【发布时间】:2021-08-28 18:34:16 【问题描述】:

类似问题

首先,我很确定必须在某个地方回答类似的问题,但我一直没能找到它。以下是一些我不想要的类似页面:

mysql - UPDATE query based on SELECT Query 那是计算两行之间的时间差,两行的 ID 都已经知道,在我的情况下,我不知道前一行的 ID 是什么。另外,当我的表是一个简单的 Unix 时间戳时,使用 DATETIME。

Calculate the time difference between two timestamps in mysql 似乎依赖于与特定 TIMESTAMP 类型相关的函数。

Difference between current and previous timestamp 似乎在问正确的事情,但他的表没有实际的时间戳,我无法得到任何答案。

MySQL: how to get the difference between two timestamps in seconds 这个是无关的。我的时间已经在时间戳中,所以我可以减去。

Calculate delta(difference of current and previous row) mysql group by specific column 这个非常接近,但它是一个 SELECT 查询,我正在尝试更新表以在新列中包含此信息,以便我可以在后续查询中使用它。它使用的 DATEDIFF 可能很容易转换为简单的减法。我真的不想在几秒钟内设置一个包含所有可能差异值的新表。

我要做什么

在 Excel 中,我可以获取行,按“时间戳”列对它们进行排序,然后设置一个新列(称为“增量”),该列等于一个时间戳减去前一个时间戳。所以我会得到一个以秒为单位的值,它是一个时间戳和前一个时间戳之间经过的时间。例如,如果一行比前一行晚 1 秒,则该值将为“1”,或者如果晚一分钟,则该值为“60”。所有时间戳都是 Unix 时间戳,因此距离 1970 年 1 月 1 日只有几秒​​钟。

在 MySQL 中添加新列很容易,但我似乎找不到合适的查询来填充它。

这是一个填充了 delta 列的示例表:

id timestamp delta
3 1623400800 NULL
2 1623444000 43200
56 1623444060 60

解决方案约束

理想情况下,由于有很多行,为了提高效率,我想要一些功能类似于我在 Excel 中所做的事情。即对表进行排序,并根据排序后的表的数据填充delta。

当然,如果这不可能,那么必须进行单独搜索以填充每一行的“增量”的查询暂时可能是可以接受的。我只需要在部分数据上运行它很多次。

【问题讨论】:

【参考方案1】:

你只需使用lag():

select t.*,
       (timestamp - lag(timestamp) over (order by timestamp)) as delta
from t;

在旧版本的 MySQL 中,您可以使用变量来相当痛苦地做到这一点:

select t.*,
       (timestamp -
        (case when (@tempt := @prevt) = null    -- never happens
              then 0
              when (@prev := timestamp) = null  -- never happens
              then 0
              else @tempt
         end)
        ) as delta
from (select t.* from t order by timestamp) t cross join
     (select @prevt := -1) params;

请注意,这使用case 表达式来实现变量处理的“顺序”逻辑。这是一个 hack,您可以理解为什么 MySQL 转而使用 标准 窗口函数进行此类操作。

您可以尝试在(timestamp) 上建立索引以提高性能。

编辑:

如果您在timestamp 上有一个索引并且时间戳是唯一的,那么您可以这样做:

update t join
       (select t.*,
               (timestamp - lag(timestamp) over (order by timestamp)) as delta
        from t
       ) tt
       using (timestamp)
    set t.delta = tt.delta;

【讨论】:

谢谢戈登!这看起来真的很有用,我会进一步研究。知道如何将该 SELECT 查询转换为将填充我添加的增量列的 UPDATE 查询吗? (一旦有了 delta,我想用它做更多的事情。) 将查询加入原表并设置delta = t1 delta 谢谢nbk。我已经使用了几次 join,但是看到您想到的查询肯定会非常有帮助。我会四处玩耍并阅读更多内容,看看我是否也能弄清楚。 非常感谢您的询问。目前,我收到“您的 SQL 语法有错误;请查看与您的 MySQL 服务器版本相对应的手册,了解在 'OVER (ORDER BY timestamp)) AS delta 附近使用的正确语法.我认为括号可能有点错误,但不确定。我设法得到“您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以通过移动方括号在“(ORDER BY timestamp)AS delta FROM”附近使用正确的语法周围,​​但无法超越。我会继续玩它的。再次感谢! 我的版本不支持 LAG 功能,因为这只是在 MySQL 8 版本中添加的。 (我使用的共享托管环境仍在 MySQL 5 上。)这里有一个链接,其中包含我正在查看的一些解决方法:***.com/questions/11303532/…

以上是关于带有 UNIX 时间戳的 MySQL 表 - 按时间戳排序并计算一行与前一行之间的差异的主要内容,如果未能解决你的问题,请参考以下文章

时间戳的函数中

将 Excel 电子表格导出到带有时间戳的访问表?

带有在单独表中定义的时间戳的 SQL EXCLUDE 记录

MySQL常见面试题-2

将数据插入另一个表时触发以更新带有时间戳的表

LIKE 声明中的%和_是什么意思?