Hive_HQL_复杂SQL_连续发单天数
原文地址:
1.Hive SQL复杂场景实现(1) —— 连续发单天数
https://blog.csdn.net/Adrian_Wang/article/details/89791948
至今在数据分析岗摸爬滚打已有一年,尚且不敢说自己挖掘洞见的本事提升多少。但实打实的与SQL打了一年的交道,接触过各种各样的业务场景,完成过各种千奇百怪的需求,自我感觉在sql编程上也颇有体会。
相信接触过SQL的人都明白知道其非常容易上手,作为一个结构化查询语言,其在数据提取上给人们提供了非常大的便捷。然而在考虑到开发成本和计算的复杂度的情况下,并非所有的提数需求都适合用sql来实现,也并非sql能够在各种业务场景下提供数据提取的最优解。有些时候hive streaming、spark、甚至简单的python脚本都能把sql难以实现的逻辑变得得心应手。即便如此,探究sql在一些复杂场景下的实现还是对锻炼逻辑思维很有帮助。
最近我会专门开辟一个专栏来分享这一年来我所遇到的一些比较复杂的业务场景,并力求通过纯sql的方法实现,给出我能想到的所有解法与大家分享。这也算是见证和记录自己一年来sql编程的心路历程了吧。
毕竟我的目标是data scientist呀
————————————————
背景
数据运营人员常常会需要查找活跃用户名单,而活跃用户很多情况下被定义为连续在线或发单n天及以上的用户。一方面我们可以根据n的值直接进行筛选;更具一般性地,就要求我们去求取每个用户某段时间内的最大连续在线或者发单天数了。
SQL求连续在线天数是一个非常经典的问题,该问题在不考虑计算成本下有非常多的解法。该问题也是我在面试实习生时最喜欢深入问的一个问题,在引导一个候选人去完成这个问题的过程中可以看出其对sql的理解深度以及其思维是否灵敏。
该问题的最大难点在于如何判断日期与日期间是否连续,那这就要涉及到处理行与行之间的关系了。说到这对SQL比较熟悉的同学应该就会反应出使用join或者窗口函数来处理了。
数据:
假设我们有19年一月份每日用户发单数据存储于订单表order_base:
user_id | order_id | create_time |
---|---|---|
234520012 | 1231512416323 | 2019-01-02 12:21:11 |
123149908 | 2412298719221 | 2019-01-04 01:11:34 |
… | … | … |
相关解法
解法1(通过与特定日期的日期差判定连续):
本方法比较tricky。连续的时间以为着这些时间点与某一个特定时间点的时间差也是连续的,从下表可以直观理解这一点:
日期 | 特定日期 | 日期差d |
2019-01-01 | 2019-01-01 | 0 |
2019-01-02 | 2019-01-01 | 1 |
2019-01-04 | 2019-01-01 | 3 |
2019-01-05 | 2019-01-01 | 4 |
2019-01-06 | 2019-01-01 | 5 |
那么我们对该日期差d进行个排序,如果连续的话,d与序号的差值应该是相同的,如下表:
日期 | 特定日期 | 日期差d | 序号r | 日期差d与序号r的差值 |
2019-01-01 | 2019-01-01 | 0 | 0 | 0 |
2019-01-02 | 2019-01-01 | 1 | 1 | 0 |
2019-01-04 | 2019-01-01 | 3 | 2 | 1 |
2019-01-05 | 2019-01-01 | 4 | 3 | 1 |
2019-01-06 | 2019-01-01 | 5 | 4 | 1 |
这样答案就显而易见了,只需要对上面这个子查询的最后一列进行分组统计行数,变得到了每次连续的天数,再取连续天数的最大值,便是我们想要的答案。
select
user_id,
max(date_cnt) as max_continuation_date_cnt
from
(
select
user_id,
d-d_ranking as d_group, -- 连续日期的组标记
count(1) as date_cnt
from
(
select
user_id,
d, --与标记日期的日期差
row_number() over(partition by user_id order by d) as d_ranking --与标记日期的日期差的排序
from
(
select
user_id,
datediff(create_date,'2019-01-01') as d --与标记日期的日期差
from
(
select
user_id,
to_date(create_time) as create_date
from
order_base
group by
user_id,
date(create_time)
)a -- 在这一层获取用户的发单日期并去重
)b --这一层获取与标记日期的日期差
)c --获取连续日期的排序
group by
user_id,
d-d_ranking
)d -- 获取每一个连续日期组的连续天数
group by
user_id
解法2(left join进行笛卡尔积):
假设我们不需要知道用户最大的连续天数,只需要知道某个用户是否出现连续n天(假设n为3)登录的行为。那这里首先给出一种完全不考虑计算复杂度的解法,使用纯join关联去实现该问题。
整体思路是去获得同一个用户的发单日期对,看每一个发单日期的n天内是否有n个发单日期。
select
user_id
from
(
select
user_id,
to_date(create_time) as create_date
from
order_base
group by
user_id,
date(create_time)
)a -- 在这一层获取用户的发单日期并去重
left join
(
select
user_id,
to_date(create_time) as create_date
from
order_base
group by
user_id,
to_date(create_time)
)b -- 与a完全相同的逻辑,为了得到日期与日期间的关联
on
a.user_id = b.user_id --仅使用user_id进行关联,获取同一个用户发单日期间的笛卡尔积
where
a.create_date <= b.create_date
and date_add(a.create_date,3) > b.create_date --以a的日期为基准,保留从a.create_date开始的3天内发单日期
group by
user_id,
a.create_date
having
count(1) = 3 --如果从a.create_date开始的3天内都有发单,则应该有3条记录
该方法容易理解,但其最大的弊端在于关联时造成的笛卡尔积大大增加了计算的复杂度。在较小的数据集上可以考虑该方法,但实际生产环境下意义并不大。
解法3 (lead或lag):
这里 使用到了 HIVE 窗口函数 LAG LEAD, 不熟悉的同学请参考 我的文章 :
1. HIVE_HIVE函数_窗口函数_LAG()/LEAD() 详解
https://blog.csdn.net/u010003835/article/details/106739353
最后介绍一个最为直观,也是计算成本最小的方法。假设我们需要求连续登陆n天(假设n为7)及以上的用户,那么对于一个存在该行为的用户,他去重和排序后的发单日期信息中,必存在某一天,往前回溯(往后推)6条记录的日期,等于该日期减6(加6)。这么说可能不太好理解,但相信你看了以下代码便能很快明白我在说什么:
select
user_id
from
(
select
user_id,
create_date,
lag(create_date,6,null) over(partition by user_id order by create_date) as last_6_row -- 按时间排序后6行之前的那一条记录
(
select
user_id,
to_date(create_time) as create_date
from
order_base
group by
user_id,
date(create_time)
)a -- 在这一层获取用户的发单日期并去重
)b --获取6行之前的那一条记录
where
datediff(create_date,last_6_row) = 6
group by
user_id
总结:
如我在介绍问题背景的时候所说,处理日期间的连续性就需要将行与行之间进行关联,而sql提供的解决方案是join和窗口函数。恰恰sql的优势便在于刻画这种行数据间的关系,该问题场景能够帮助我们更深入地理解SQL的这一特性。
Hive_HQL_复杂SQL_连续发单天数相关推荐
- Hive SQL复杂场景实现(1) —— 连续发单天数
本文同时发表于我的个人博客http://xinyuwg.com,访问该链接以获得详细信息与更好的阅读体验. 本文为原创内容,未经允许请勿转载. 至今在数据分析岗摸爬滚打已有一年,尚且不敢说自己挖掘洞见 ...
- Hive SQL— 连续发单天数
背景 数据运营人员常常会需要查找活跃用户名单,而活跃用户很多情况下被定义为连续在线或发单n天及以上的用户.一方面我们可以根据n的值直接进行筛选:更具一般性地,就要求我们去求取每个用户某段时间内的最大连 ...
- mysql 连续签到天数_天天拿帮会通宝 帮会签到真给力
在<天龙八部手游>中,绝大多数少侠都拥有自己的帮会,每天和帮会兄弟姐妹们做着各种帮会活动,大家彼此配合默契,荣辱与共,其乐融融.为了尽可能地满足少侠对帮会通宝的需求,现在帮会又多了一项帮会 ...
- mysql 连续签到天数_新版签到活动明天上线,福利活动抢鲜看~
明天游戏中心app旧版福利签到活动马上就要结束啦,虽然很多的魅友反馈说积分签到结束的太早,积分不够换5折券,不过更早的开启新版签到才能更快的享受到更好的福利嘛~ 今晚0点新版签到活动即将上线,接下来就 ...
- mysql 连续签到天数_签到功能实现,没有你想的那么复杂(一)
1 签到定义以及作用签到,指在规定的簿册上签名或写一"到"字,表示本人已经到达.在APP中使用此功能,可以增加用户粘性和活跃度.2 技术选型redis为主写入查询,mysql辅助查 ...
- Python应用实战-Pandas 计算连续行为天数的几种思路
最近在处理数据的时候遇到一个需求,核心就是求取最大连续行为天数. 这里用北京空气质量数据作为案例进行演示,需求是找出北京空气质量连续污染最长持续多久并确定其周期. 图1:案例数据 以上图中数据来算,可 ...
- sql server计算日期到当前日期天数_Excel如何统计连续停机天数问题
前几天有个朋友问了一个关于连续时间统计的问题,使用Power Query for Excel来解决的.今天在张俊红老师的公众号上看到了使用使用SQL来解决连续时间的统计问题.这个问题是一个非常经典的例 ...
- mysql 连续天数_mysql计算连续天数,mysql连续登录天数,连续天数统计
mysql计算连续天数,mysql连续登录天数,连续天数统计 >>>>>>>>>>>>>>>>>& ...
- Hive sql : 查询连续登录天数
查询连续登录天数 1.问题描述 2.在Hive中建表 3.查询最大连续登录天数 1.问题描述 目前有两列数据,分别是用户ID和用户登录的时间,现需要统计用户连续登录的最大天数,中间如有断开,则不算连续 ...
最新文章
- 血亏 1.5 亿、华为断供、Linux 之父怒删代码,2020 IT 大事记盘点
- UA OPTI512R 傅立叶光学导论15 2-D Fourier变换与Hankel变换
- 基于FPGA的目标点的提取与定位系统设计
- Redis 集合(Set)
- 如何更换outlook邮件的背景色
- java类编写sql_用JavaBean编写SQL Server数据库连接类
- python是什么 自学-自学python需要什么基础,要掌握哪些知识?
- c语言删除元素1116,C语言网蓝桥杯1116 IP判断
- Fragment中获取Activity的Context
- android自动计步_Android计步模块实例代码(类似微信运动)
- HLI测试 涉及书籍
- EasyAR WebAR开发
- 引入tinymce-vue后调试器报错 Refused to apply styl
- 获取google chrome浏览器的安装位置
- 《华为工作法》8 自我提升的华为人
- 7-8 哈利·波特的考试 (25 分)(Floyd算法)
- Teaching Machines to Read and Comprehend翻译
- 记录第一次使用nvidia tao训练模型的过程
- 2020年美国大学计算机科学专业排名,美国大学计算机排名2020年最新排名
- 洛谷P1498 南蛮图腾(递归,找规律)
热门文章
- 蓝奏云链接打不开的解决办法
- ZZNUOJ_C语言1134:字符串转换(附完整源码)
- led和白炽灯哪个对眼睛好?分享光线舒适的LED护眼灯
- 广州王师傅揭秘未来20年最有前途的行业!——不要再错过下一个风口
- 智能电表DLT698.45-2017协议规约红外无线抄表报文解析示例说明
- 华为P30 后摄像头打不开(C1904失效)维修案例
- Glib学习(17) Key-value文件解析器 Key-value file parser
- 那些清华北大随便挑的高考状元们,后来都过上了怎样的生活?
- Imperva常用的维护命令
- Imperva WAF Bypass【翻译】