【MySQL】窗口函数 Lead 和 Lag 的运用(MySQL版本8+)以及 时间差函数 TIMESTAMPDIFF 的运用

本文主要是介绍【MySQL】窗口函数 Lead 和 Lag 的运用(MySQL版本8+)以及 时间差函数 TIMESTAMPDIFF 的运用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

力扣题

1、题目地址

1939. 主动请求确认消息的用户

2、模拟表

表:Signups

Column NameType
user_idint
time_stampdatetime
  • user_id is the primary key for this table.
  • 每行包含有关 ID 为 user_id 的用户的注册时间的信息。

表:Confirmations

Column NameType
user_idint
time_stampdatetime
actionENUM
  • (user_id, time_stamp) is the primary key for this table.
  • user_id is a foreign key with a reference to the Signups table.
  • action is an ENUM of the type (‘confirmed’, ‘timeout’)
  • 此表的每一行都表示 ID 为 user_id 的用户在 time_stamp 请求了确认消息,
  • 并且该确认消息已被确认(‘confirmed’)或已过期(‘timeout’)。

3、要求

编写 SQL 查询以查找在 24 小时窗口内两次请求确认消息的用户的 ID。
两个正好相隔 24 小时的消息被认为是在窗口内。 该操作不会影响答案,只会影响请求时间。

以任意顺序返回结果表。

查询结果格式如下例:

Signups 表:

user_idtime_stamp
32020-03-21 10:16:13
72020-01-04 13:57:59
22020-07-29 23:09:44
62020-12-09 10:39:37

Confirmations 表:

user_idtime_stampaction
32021-01-06 03:30:46timeout
32021-01-06 03:37:45timeout
72021-06-12 11:57:29confirmed
72021-06-13 11:57:30confirmed
22021-01-22 00:00:00confirmed
22021-01-23 00:00:00timeout
62021-10-23 14:14:14confirmed
62021-10-24 14:14:13timeout

输出:

user_id
2
3
6

解析:
用户 2 在彼此恰好 24 小时内请求了两条消息,因此我们将它们包括在内。
用户 3 在 6 分 59 秒内请求了两条消息,因此我们将它们包括在内。
用户 6 在 23 小时 59 分 59 秒内请求了两条消息,因此我们将它们包括在内。
用户 7 在 24 小时 1 秒内请求了两条消息,因此我们将它们从答案中排除。

4、代码编写

知识点(先看这个方便理解代码)

TIMESTAMPDIFF ⭐️

语法: TIMESTAMPDIFF (interval, datetime_expr1, datetime_expr2)

说明: 返回结果 datetime_expr2 - datetime_expr1

参数: interval 可以为 SECOND - 秒、MINUTE - 分、HOUR - 时、DAY - 日、MONTH - 月、YEAR - 年

mysql> SELECT TIMESTAMPDIFF(DAY,'2024-01-03','2024-01-01'); 
-> -2
mysql> SELECT TIMESTAMPDIFF(DAY,'2024-01-01','2024-01-03'); 
-> 2

参考:MySQL – 计算时间差

Lead 和 Lag⭐️

语法:
Lead (列名, 偏移量, 超出记录窗口时的默认值)
Lag (列名, 偏移量, 超出记录窗口时的默认值)
注:如果使用 Lead (列名) 或 Lag (列名) 语法,则偏移量默认1,默认值是 null(无显示)

说明:
Lead:形象的理解就是把数据从下向上推,下端出现空格
Lag:形象的理解就是把数据从上向下推,上端出现空格

原始数据 (items):

item_iditem_brand
1Samsung
2Lenovo
3LG
4HP

Lead代码效果

SELECT *, Lead(item_brand, 1, 0) OVER (ORDER BY item_id) AS lead_data
FROM items
item_iditem_brandlead_data
1SamsungLenovo
2LenovoLG
3LGHP
4HP0

Lag代码效果

SELECT *, Lag(item_brand, 1, 0) OVER (ORDER BY item_id) AS lag_data
FROM items
item_iditem_brandlag_data
1Samsung0
2LenovoSamsung
3LGLenovo
4HPLG

参考:sql中的窗口函数:lead,lag

1、TIMESTAMPDIFF 配合 Lead 写法

SELECT DISTINCT user_id
FROM (SELECT user_id, TIMESTAMPDIFF(SECOND, time_stamp, LEAD(time_stamp, 1, 0) OVER (PARTITION BY user_id ORDER BY time_stamp)) AS diffFROM Confirmations
) AS one
WHERE diff IS NOT NULL
AND diff <= 24*60*60

代码分析

SELECT user_id, TIMESTAMPDIFF(SECOND, time_stamp, LEAD(time_stamp, 1, 0) OVER (PARTITION BY user_id ORDER BY time_stamp)
) AS diff
FROM Confirmations

Lead的效果是下向上推,例如

| 2       | 2021-01-22 00:00:00 |
| 2       | 2021-01-23 00:00:00 |

变成

| 2       | 2021-01-23 00:00:00 |
| 2       | null |

利用向上推的数据减去原先的数据,
上面SQL语句 TIMESTAMPDIFF 的第二个参数是 2021-01-22 00:00:00,第三个参数是 2021-01-23 00:00:00
下面出现空格,默认值null(无显示)没错,

| user_id | diff  |
| ------- | ----- |
| 2       | 86400 |
| 2       | null  |
| 3       | 419   |
| 3       | null  |
| 6       | 86399 |
| 6       | null  |
| 7       | 86401 |
| 7       | null  |

要小于等于86400(一天)里面只有三个符合要求

| user_id | diff  |
| ------- | ----- |
| 2       | 86400 |
| 3       | 419   |
| 6       | 86399 |

2、TIMESTAMPDIFF 配合 Lag 写法

SELECT DISTINCT user_id
FROM (SELECT user_id, TIMESTAMPDIFF(SECOND, time_stamp, LAG(time_stamp, 1, 0) OVER (PARTITION BY user_id ORDER BY time_stamp)) AS diffFROM Confirmations
) AS one
WHERE diff IS NOT NULL
AND ABS(diff) <= 24*60*60

Lag的效果是上向下推,例如

| 2       | 2021-01-22 00:00:00 |
| 2       | 2021-01-23 00:00:00 |

变成

| 2       | null |
| 2       | 2021-01-22 00:00:00 |

利用向上推的数据减去原先的数据,
上面SQL语句 TIMESTAMPDIFF 的第二个参数是 2021-01-23 00:00:00,第三个参数是 2021-01-22 00:00:00
上面出现空格,默认值null(无显示)没错,

| user_id | diff   |
| ------- | ------ |
| 2       | null   |
| 2       | -86400 |
| 3       | null   |
| 3       | -419   |
| 6       | null   |
| 6       | -86399 |
| 7       | null   |
| 7       | -86401 |

要小于等于86400(一天)里面只有三个符合要求(需要取绝对值)

| user_id | diff  |
| ------- | ----- |
| 2       | -86400 |
| 3       | -419   |
| 6       | -86399 |

你要简单写就把 TIMESTAMPDIFF 参数二和参数三换个位置就不用取绝对值了,主要还是演示多种情况,方便更好理解

SELECT DISTINCT user_id
FROM (SELECT user_id, TIMESTAMPDIFF(SECOND, LAG(time_stamp, 1, 0) OVER (PARTITION BY user_id ORDER BY time_stamp), time_stamp) AS diffFROM Confirmations
) AS one
WHERE diff IS NOT NULL
AND diff <= 24*60*60

注:ABS() 函数的效果和数学中的绝对值效果一样

3、单 TIMESTAMPDIFF 写法

有限制正范围的情况就只保证两个时间不相同即可(a.time_stamp != b.time_stamp 是为了不和自己连接,因为没有唯一键做区分)

SELECT DISTINCT a.user_id
FROM Confirmations a, Confirmations b
WHERE a.user_id = b.user_id
AND TIMESTAMPDIFF(SECOND, a.time_stamp, b.time_stamp) BETWEEN 0 AND 24*60*60
AND a.time_stamp != b.time_stamp

包含负范围的情况就还得控制算出的时间差是正的(b.time_stamp - a.time_stamp > 0)

SELECT DISTINCT a.user_id
FROM Confirmations a, Confirmations b
WHERE a.user_id = b.user_id
AND TIMESTAMPDIFF(SECOND, a.time_stamp, b.time_stamp) <= 86400
AND a.time_stamp < b.time_stamp

这篇关于【MySQL】窗口函数 Lead 和 Lag 的运用(MySQL版本8+)以及 时间差函数 TIMESTAMPDIFF 的运用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/569098

相关文章

一文详解MySQL如何设置自动备份任务

《一文详解MySQL如何设置自动备份任务》设置自动备份任务可以确保你的数据库定期备份,防止数据丢失,下面我们就来详细介绍一下如何使用Bash脚本和Cron任务在Linux系统上设置MySQL数据库的自... 目录1. 编写备份脚本1.1 创建并编辑备份脚本1.2 给予脚本执行权限2. 设置 Cron 任务2

SQL Server修改数据库名及物理数据文件名操作步骤

《SQLServer修改数据库名及物理数据文件名操作步骤》在SQLServer中重命名数据库是一个常见的操作,但需要确保用户具有足够的权限来执行此操作,:本文主要介绍SQLServer修改数据... 目录一、背景介绍二、操作步骤2.1 设置为单用户模式(断开连接)2.2 修改数据库名称2.3 查找逻辑文件名

SQL Server数据库死锁处理超详细攻略

《SQLServer数据库死锁处理超详细攻略》SQLServer作为主流数据库管理系统,在高并发场景下可能面临死锁问题,影响系统性能和稳定性,这篇文章主要给大家介绍了关于SQLServer数据库死... 目录一、引言二、查询 Sqlserver 中造成死锁的 SPID三、用内置函数查询执行信息1. sp_w

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

canal实现mysql数据同步的详细过程

《canal实现mysql数据同步的详细过程》:本文主要介绍canal实现mysql数据同步的详细过程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的... 目录1、canal下载2、mysql同步用户创建和授权3、canal admin安装和启动4、canal

使用jenv工具管理多个JDK版本的方法步骤

《使用jenv工具管理多个JDK版本的方法步骤》jenv是一个开源的Java环境管理工具,旨在帮助开发者在同一台机器上轻松管理和切换多个Java版本,:本文主要介绍使用jenv工具管理多个JD... 目录一、jenv到底是干啥的?二、jenv的核心功能(一)管理多个Java版本(二)支持插件扩展(三)环境隔

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用

MySQL存储过程之循环遍历查询的结果集详解

《MySQL存储过程之循环遍历查询的结果集详解》:本文主要介绍MySQL存储过程之循环遍历查询的结果集,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言1. 表结构2. 存储过程3. 关于存储过程的SQL补充总结前言近来碰到这样一个问题:在生产上导入的数据发现

MySQL 衍生表(Derived Tables)的使用

《MySQL衍生表(DerivedTables)的使用》本文主要介绍了MySQL衍生表(DerivedTables)的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学... 目录一、衍生表简介1.1 衍生表基本用法1.2 自定义列名1.3 衍生表的局限在SQL的查询语句select