SQL之一种通用的连续性问题处理方法【重分组算法】--HiveSQL面试题33
目录
0 需求分析
1 数据准备
2 数据分析
3 小 结
0 需求分析
数据如下:
wang | 2020-05-01 |
wang | 2020-05-01 |
wang | 2020-05-01 |
wang | 2020-05-02 |
wang | 2020-05-03 |
wang | 2020-05-04 |
wang | 2020-05-07 |
zhao | 2020-04-01 |
zhao | 2020-04-01 |
zhao | 2020-04-07 |
zhao | 2020-05-09 |
zhao | 2020-05-10 |
li | 2020-01-10 |
li | 2020-01-12 |
li | 2020-04-12 |
li | 2020-01-13 |
li | 2020-01-13 |
li | 2020-01-14 |
li | 2020-02-12 |
li | 2020-02-13 |
li | 2020-02-14 |
求:每个用户连续登陆的最大天数
1 数据准备
(1)数据
vim usr_login
wang 2020-05-01
wang 2020-05-01
wang 2020-05-02
wang 2020-05-03
wang 2020-05-04
wang 2020-05-07
zhao 2020-04-01
zhao 2020-04-01
zhao 2020-04-07
zhao 2020-05-09
zhao 2020-05-10
li 2020-01-10
li 2020-01-12
li 2020-04-12
li 2020-01-13
li 2020-01-13
li 2020-01-14
li 2020-02-12
li 2020-02-13
li 2020-02-14
(2)建表
drop table if exists usr_login
CREATE TABLE dan_test.usr_login ( user_id string, login_date string)
ROW format delimited FIELDS TERMINATED BY "\t";
(3)加载数据
load data local inpath "/home/centos/dan_test/usr_login.txt" into table usr_login;
(4) 查询数据
hive> select * from usr_login;
OK
wang 2020-05-01
wang 2020-05-01
wang 2020-05-01
wang 2020-05-02
wang 2020-05-03
wang 2020-05-04
wang 2020-05-07
zhao 2020-04-01
zhao 2020-04-01
zhao 2020-04-07
zhao 2020-05-09
zhao 2020-05-10
li 2020-01-10
li 2020-01-12
li 2020-04-12
li 2020-01-13
li 2020-01-13
li 2020-01-14
li 2020-02-12
li 2020-02-13
li 2020-02-14
Time taken: 0.16 seconds, Fetched: 21 row(s)
2 数据分析
思路:将每次连续的数据分成一组,求每组中连续的天数,在对每个用户求最大天数
问题:如何将每次连续的数据分成一组。
思路:借助按事件变化后重分组算法
(1)求出每组中相邻数据的差值
selectuser_id,login_date,datediff(login_date,lag(login_date,1,login_date) over(partition by user_id order by login_date)) as login_date_diff
from usr_login
计算结果如下:
--------------------------------------------------------------------------------
OK
li 2020-01-10 0
li 2020-01-12 2
li 2020-01-13 1
li 2020-01-13 0
li 2020-01-14 1
li 2020-02-12 29
li 2020-02-13 1
li 2020-02-14 1
li 2020-04-12 58
wang 2020-05-01 0
wang 2020-05-01 0
wang 2020-05-01 0
wang 2020-05-02 1
wang 2020-05-03 1
wang 2020-05-04 1
wang 2020-05-07 3
zhao 2020-04-01 0
zhao 2020-04-01 0
zhao 2020-04-07 6
zhao 2020-05-09 32
zhao 2020-05-10 1
Time taken: 9.813 seconds, Fetched: 21 row(s)
(2) 获取分组id
我们希望的是将连续的数据分成一组,如下图所示
由于是连续的所以相邻的两行差值为1,注意到有重复数据,所以差值可能也为0,因此我们需要将差值大于1的数据进行标记并进行累加得到分组id。注意重分组一般是不等情况,且考虑方面情况,具有完备性。分析出正常情况的满足值,条件中考虑其补集,这是关键,和易错点。
具体SQL如下:
select user_id,login_date,login_date_diff,sum(if(login_date_diff>1,1,0)) over(partition by user_id order by login_date)
from(selectuser_id,login_date,datediff(login_date,lag(login_date,1,login_date) over(partition by user_id order by login_date)) as login_date_difffrom usr_login
) m
计算结果如下:
--------------------------------------------------------------------------------
OK
li 2020-01-10 0 0
li 2020-01-12 2 1
li 2020-01-13 1 1
li 2020-01-13 0 1
li 2020-01-14 1 1
li 2020-02-12 29 2
li 2020-02-13 1 2
li 2020-02-14 1 2
li 2020-04-12 58 3
wang 2020-05-01 0 0
wang 2020-05-01 0 0
wang 2020-05-01 0 0
wang 2020-05-02 1 0
wang 2020-05-03 1 0
wang 2020-05-04 1 0
wang 2020-05-07 3 1
zhao 2020-04-01 0 0
zhao 2020-04-01 0 0
zhao 2020-04-07 6 1
zhao 2020-05-09 32 2
zhao 2020-05-10 1 2
Time taken: 14.228 seconds, Fetched: 21 row(s)
(3)按照步骤2获取的分组id进行分组,计算同一分组内的最大、最小值的差值
select user_id,grp_id,datediff(max(login_date),min(login_date))+1
from(select user_id,login_date,login_date_diff,sum(if(login_date_diff > 1,1,0)) over(partition by user_id order by login_date) as grp_idfrom(selectuser_id,login_date,datediff(login_date,lag(login_date,1,login_date) over(partition by user_id order by login_date)) as login_date_difffrom usr_login) m
)n
group by user_id,grp_id
计算结果如下:
--------------------------------------------------------------------------------
OK
li 0 1
li 1 3
li 2 3
li 3 1
wang 0 4
wang 1 1
zhao 0 1
zhao 1 1
zhao 2 2
Time taken: 11.745 seconds, Fetched: 9 row(s)
(4)基于步骤3求出最大值
最终SQL如下:
select user_id,max(diff) as max_diff
from(select user_id,grp_id,datediff(max(login_date),min(login_date))+1 as difffrom(select user_id,login_date,login_date_diff,sum(if(login_date_diff > 1,1,0)) over(partition by user_id order by login_date) as grp_idfrom(selectuser_id,login_date,datediff(login_date,lag(login_date,1,login_date) over(partition by user_id order by login_date)) as login_date_difffrom usr_login) m)ngroup by user_id,grp_id
) t
group by user_id
最终计算结果如下:
--------------------------------------------------------------------------------
OK
li 3
wang 4
zhao 2
Time taken: 11.165 seconds, Fetched: 3 row(s)
3 小 结
本文构建的方法对于求连续性问题具有一定的通用性,无论求连续多少天的都可以通过本方法求出,因为该方法试图将每个连续的数据分到一个组里,求出每个连续的组里的连续天数,因而具有通用性。当然对于连续性问题一般意义而言是相邻间隔为1,如果有题目定义间隔为1,间隔为2等等也为连续,那么本题给出的方法也同样适用,只需要修改通用的参数即可,通用代码模板如下:其中n代表定义间隔多少为连续,如果是1n则代表1,如果为2,n则代表2,以此类推。
select user_id,max(diff) as max_diff
from(select user_id,grp_id,datediff(max(login_date),min(login_date))+1 as difffrom(select user_id,login_date,login_date_diff,sum(if(login_date_diff > n,1,0)) over(partition by user_id order by login_date) as grp_idfrom(selectuser_id,login_date,datediff(login_date,lag(login_date,1,login_date) over(partition by user_id order by login_date)) as login_date_difffrom usr_login) m)ngroup by user_id,grp_id
) t
group by user_id
欢迎关注石榴姐公众号"我的SQL呀",关注我不迷路
SQL之一种通用的连续性问题处理方法【重分组算法】--HiveSQL面试题33相关推荐
- 一种通用嵌入式LCD页面切换方法
一种通用嵌入式LCD页面切换方法 在资源较匮乏的嵌入式系统上,无法运行操作系统,此种情形下,通过按键控制LCD界面的切换时,若不采取一定的逻辑框架,在需求变动时,程序逻辑改动较大.页面逐渐增多时,前期 ...
- SQL之求股票的波峰和波谷--HiveSQL面试题33【今日头条】
目录 0 需求 1 数据准备 2 数据分析 3 小 结 0 需求:求股票的波峰Crest 和 波谷trough 波峰:当天的股票价格大于前一天和后一天 波谷:当天的股票价格小于前一天和后一天数据准备: ...
- Makefile之大型工程项目子目录Makefile的一种通用写法
原创作品,转载时请务必以超链接形式标明文章原始出处:http://blog.csdn.net/gqb666/article/details/8902133,作者:gqb666 管理Linux环境下的C ...
- 一种通用递归深度检测技术 - 基于栈帧内容的检测 - Golang语言描述
背景 在递归处理的调用中,在具体的工程实践中一般会引入递归深度检测,防止因为错误的数据造成系统的资源极大的消耗,本方法定义了一种通用简单的递归检查方法. 步骤 实现函数RecursiveDepthCh ...
- mybatis case when_MyBatis 几种通用的写法
阅读本文约需要8分钟 大家好,我是你们的导师,我每天都会在这里给大家分享一些干货内容(当然了,周末也要允许老师休息一下哈).上次老师跟大家分享了下SpringBoot 2.3 新特性之 ...
- 写给数据分析入门者:一种通用的数据分析思路
数据分析是一个庞大的工程,有的时候过于抽象且依赖经验.本文是笔者对学习和实践数据分析的一个总结,希望提供一种通用的数据分析思路,并在分析思路的每个步骤中介绍相关的分析算法及其应用场景,对于算法只做浅层 ...
- 第2讲:SQL语言的通用语法及分类
SQL语言的通用语法及分类 文章目录 SQL语言的通用语法及分类 1.SQL语言的通用语法格式 2.SQL语言的几种分类 1.SQL语言的通用语法格式 2.SQL语言的几种分类 1.SQL语言的通用语 ...
- C#毕业设计——基于C#+asp.net+SQL server的通用作业批改系统设计与实现(毕业论文+程序源码)——作业批改系统
基于C#+asp.net+SQL server的通用作业批改系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于C#+asp.net+SQL server的通用作业批改系统设计与实现,文章 ...
- PL/SQL三种集合类型的比较
PL/SQL三种集合类型的比较<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" ...
最新文章
- 指定ASP .NET Core Web应用端口
- 同是程序员,为什么别人可以事半功倍?
- python format 槽中槽_printf中的槽和实参--对比python struct包
- Java 设计模式之命令模式
- composer 设置版本号_Composer依赖管理 – PHP的利器
- 《Python编程从入门到实践》记录之第3章 列表简介总结——列表添加修改和删除元素(思维导图)
- 微信小程序怎么在wxml中插入多个图片_闲聊微信小程序开发框架(二)
- UI设计和UX设计有什么区别?
- mysql longtext 查询_mysql,_mysql中longtext存在大量数据时,会导致查询很慢?,mysql - phpStudy...
- css grid 自动高度_CSS Grid布局指南
- windows批量重命名
- dex2jar的使用
- 运维笔记-lnmp一键安装问题
- C语言中心对称图形定义,中心对称图形的定义
- iPhone 重大缺陷 存储空间耗尽后无法正常开机
- 966. 元音拼写检查器
- cocosbuilder创建工程
- cmd 更新 pip版本指令
- aiem模型matlab,基于MIMICS模型的麦田地表土壤含水量反演研究
- Laravel 使用视图合成器 view composer 实现视图变量共享
热门文章
- 机器人总动员主角简笔画_机器人总动员人物简介
- 思科AP修改AP位置描述通过WLC命令方式
- 逆战选择服务器后显示器,逆战游戏设置知识_隐藏在数据设置背后的大学问_叶子猪逆战...
- LiveNVR监控流媒体Onvif/RTSP常见问题-接入的通道没有云台控制按钮云台控制灰色无法操作怎么办?
- VLAN作用、超级vlan、转发、网课
- TCP协议为什么是三次握手而不是两次
- 性格与领导力 ——不可不知的DISC 性格学
- Java读取excel指定行列的数据(poi的方式)
- C# sha256和HmacSHA256加密
- Windows任务管理器,远比你想象中的复杂