SQL 获取最长的日期序列
时间:2022-07-22
本文章向大家介绍SQL 获取最长的日期序列,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
有一张学习打卡表 his_sign
表,简单起见,只设置了两个字段(id,create_ts)
,一个是主键,另一个是打卡时间。his_sign
表的数据如下,我们要统计出这张表里面最长的连续打卡记录。
id create_ts
------ ---------------------
1 2020-05-01 09:04:26
2 2020-05-02 11:54:45
3 2020-05-04 23:05:03
4 2020-05-06 07:12:31
5 2020-05-06 08:01:52
6 2020-05-07 22:06:48
7 2020-05-08 12:36:58
8 2020-05-09 11:49:13
9 2020-05-12 08:52:35
10 2020-05-13 23:45:57
11 2020-05-14 00:02:24
12 2020-05-14 09:24:18
13 2020-05-19 15:34:45
14 2020-05-21 21:10:02
先检查数据,我们发现在一天之内可以多次打卡,因此需要先去掉重复打卡的记录,并将字段 create_ts
使用日期格式展示。
SELECT DISTINCT
(DATE(create_ts)) AS create_ts
FROM
his_sign
去重并格式化后的数据如下:
create_ts
------------
2020-05-01
2020-05-02
2020-05-04
2020-05-06
2020-05-07
2020-05-08
2020-05-09
2020-05-12
2020-05-13
2020-05-14
2020-05-19
2020-05-21
由于数据量不大,我们观察表数据可知,2020-05-06
到 2020-05-09
是最长的序列,总共 4 天。
解题的思路就是把连续的日期编为一组,然后从多组数据中找到数量最多的一组数据,那组数据就是最长的序列。
将表里面的数据按日期的升序排序,并给每个日期分配一个连续的自然数序号,用日期减去它对应的序号,会得到一个新的日期值。我们发现,连续的日期它们对应的新的日期值为同一个,因此,这个新的日期值就是序列的组别。
找到连续日期的组的 SQL 如下:
WITH t1 AS
(SELECT DISTINCT
(DATE(create_ts)) AS create_ts
FROM
his_sign),
t2 AS
(SELECT
create_ts,
row_number () over (
ORDER BY create_ts) AS rn
FROM
t1)
SELECT
create_ts,
DATE_SUB(create_ts, INTERVAL rn DAY) AS grp
FROM
t2
上面 SQL 执行后输出的结果:
create_ts grp
---------- ------------
2020-05-01 2020-04-30
2020-05-02 2020-04-30
2020-05-04 2020-05-01
2020-05-06 2020-05-02
2020-05-07 2020-05-02
2020-05-08 2020-05-02
2020-05-09 2020-05-02
2020-05-12 2020-05-04
2020-05-13 2020-05-04
2020-05-14 2020-05-04
2020-05-19 2020-05-08
2020-05-21 2020-05-09
剩下的操作就简单多了,把数据最多的那组找出来就对了。只是需要注意,最长的序列有可能有多个,因此在找最长的序列的时候需要注意方法。
结合开窗函数 rank() over(ORDER BY xxx)
可以找到多个最长序列,完整的 SQL 如下:
# 1.去掉重复日期,并格式化
WITH t1 AS
(SELECT DISTINCT
(DATE(create_ts)) AS create_ts
FROM
his_sign),
# 2.给每个日期指定一个序号
t2 AS
(SELECT
create_ts,
row_number () over (
ORDER BY create_ts) AS rn
FROM
t1),
# 3.找到分组的依据
t3 AS
(SELECT
create_ts,
DATE_SUB(create_ts, INTERVAL rn DAY) AS grp
FROM
t2),
# 4.分组
t4 AS
(SELECT
MIN(create_ts) AS start_date,
MAX(create_ts) AS end_date,
COUNT(*) AS cnt
FROM
t3
GROUP BY grp),
# 5.对所有序列按照长度降序排序
t5 AS
(SELECT
*,
rank () over (
ORDER BY cnt DESC) AS rk
FROM
t4)
# 6.只选择最长的序列
SELECT
start_date,
end_date,
cnt
FROM
t5
WHERE rk = 1
输出:
start_date end_date cnt
---------- ---------- --------
2020-05-06 2020-05-09 4
为了让大家看得更明白,我用 CTE 表达式把每个过程都写出来了。每段表达式都加了注释,理解起来应该不难。
注意,上述的 SQL 需要在 MySQL 8.0 + 环境里才能正常执行。
- Apache Spark 2.0预览:机器学习模型持久性
- 推荐一个简单、轻量、功能非常强大的C#/ASP.NET定时任务执行管理器组件–FluentScheduler
- 携程Android App的插件化和动态加载框架
- Spring Boot构建RESTful API与单元测试
- Volley解析之表单提交篇
- JAVA中重写equals()方法的同时要重写hashcode()方法
- 调用CodeSmith类库实现代码生成(含源码)
- 1分钟生成Net对象的注释
- Android Studio之gradle的配置与介绍
- MLlib中的随机森林和提升方法
- android JNI调用机制
- Android开发小窍门通过泛型简化findViewById类型转换
- lodash源码分析之缓存使用方式的进一步封装
- Android LruCache技术原理
- MySQL 教程
- MySQL 安装
- MySQL 管理与配置
- MySQL PHP 语法
- MySQL 连接
- MySQL 创建数据库
- MySQL 删除数据库
- MySQL 选择数据库
- MySQL 数据类型
- MySQL 创建数据表
- MySQL 删除数据表
- MySQL 插入数据
- MySQL 查询数据
- MySQL where 子句
- MySQL UPDATE 查询
- MySQL DELETE 语句
- MySQL LIKE 子句
- mysql order by
- Mysql Join的使用
- MySQL NULL 值处理
- MySQL 正则表达式
- MySQL 事务
- MySQL ALTER命令
- MySQL 索引
- MySQL 临时表
- MySQL 复制表
- 查看MySQL 元数据
- MySQL 序列 AUTO_INCREMENT
- MySQL 处理重复数据
- MySQL 及 SQL 注入
- MySQL 导出数据
- MySQL 导入数据
- MYSQL 函数大全
- MySQL Group By 实例讲解
- MySQL Max()函数实例讲解
- mysql count函数实例
- MYSQL UNION和UNION ALL实例
- MySQL IN 用法
- MySQL between and 实例讲解
- Python进阶(一)
- Python版本的OpenCV安装
- CVE-2020-16875:Microsoft Exchange RCE复现
- 抢先学鸿蒙(HarmonyOS)2.0,你就是下一个大咖!
- Python高效编程之88条军规(2):你真的会格式化字符串吗?
- 搭建Typecho博客
- Python开发之Pandas的使用
- Python开发之numpy的使用
- flink sql实时计算当天pv写入mysql
- python爬取虎牙直播颜值区美女主播照片
- OpenCV图像处理笔记(三):霍夫变换、直方图、轮廓等综合应用
- 干货 | 高耦合场景下,Trip.com如何做支付设计与落地
- OpenCV图像处理笔记(二):图片操作进阶
- OpenCV图像处理笔记(一):图片基本操作
- BigData--Hadoop2.x新特性之HA