目录

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相关推荐

  1. 一种通用嵌入式LCD页面切换方法

    一种通用嵌入式LCD页面切换方法 在资源较匮乏的嵌入式系统上,无法运行操作系统,此种情形下,通过按键控制LCD界面的切换时,若不采取一定的逻辑框架,在需求变动时,程序逻辑改动较大.页面逐渐增多时,前期 ...

  2. SQL之求股票的波峰和波谷--HiveSQL面试题33【今日头条】

    目录 0 需求 1 数据准备 2 数据分析 3 小 结 0 需求:求股票的波峰Crest 和 波谷trough 波峰:当天的股票价格大于前一天和后一天 波谷:当天的股票价格小于前一天和后一天数据准备: ...

  3. Makefile之大型工程项目子目录Makefile的一种通用写法

    原创作品,转载时请务必以超链接形式标明文章原始出处:http://blog.csdn.net/gqb666/article/details/8902133,作者:gqb666 管理Linux环境下的C ...

  4. 一种通用递归深度检测技术 - 基于栈帧内容的检测 - Golang语言描述

    背景 在递归处理的调用中,在具体的工程实践中一般会引入递归深度检测,防止因为错误的数据造成系统的资源极大的消耗,本方法定义了一种通用简单的递归检查方法. 步骤 实现函数RecursiveDepthCh ...

  5. mybatis case when_MyBatis 几种通用的写法

           阅读本文约需要8分钟  大家好,我是你们的导师,我每天都会在这里给大家分享一些干货内容(当然了,周末也要允许老师休息一下哈).上次老师跟大家分享了下SpringBoot 2.3 新特性之 ...

  6. 写给数据分析入门者:一种通用的数据分析思路

    数据分析是一个庞大的工程,有的时候过于抽象且依赖经验.本文是笔者对学习和实践数据分析的一个总结,希望提供一种通用的数据分析思路,并在分析思路的每个步骤中介绍相关的分析算法及其应用场景,对于算法只做浅层 ...

  7. 第2讲:SQL语言的通用语法及分类

    SQL语言的通用语法及分类 文章目录 SQL语言的通用语法及分类 1.SQL语言的通用语法格式 2.SQL语言的几种分类 1.SQL语言的通用语法格式 2.SQL语言的几种分类 1.SQL语言的通用语 ...

  8. C#毕业设计——基于C#+asp.net+SQL server的通用作业批改系统设计与实现(毕业论文+程序源码)——作业批改系统

    基于C#+asp.net+SQL server的通用作业批改系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于C#+asp.net+SQL server的通用作业批改系统设计与实现,文章 ...

  9. PL/SQL三种集合类型的比较

    PL/SQL三种集合类型的比较<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" ...

最新文章

  1. 指定ASP .NET Core Web应用端口
  2. 同是程序员,为什么别人可以事半功倍?
  3. python format 槽中槽_printf中的槽和实参--对比python struct包
  4. Java 设计模式之命令模式
  5. composer 设置版本号_Composer依赖管理 – PHP的利器
  6. 《Python编程从入门到实践》记录之第3章 列表简介总结——列表添加修改和删除元素(思维导图)
  7. 微信小程序怎么在wxml中插入多个图片_闲聊微信小程序开发框架(二)
  8. UI设计和UX设计有什么区别?
  9. mysql longtext 查询_mysql,_mysql中longtext存在大量数据时,会导致查询很慢?,mysql - phpStudy...
  10. css grid 自动高度_CSS Grid布局指南
  11. windows批量重命名
  12. dex2jar的使用
  13. 运维笔记-lnmp一键安装问题
  14. C语言中心对称图形定义,中心对称图形的定义
  15. iPhone 重大缺陷 存储空间耗尽后无法正常开机
  16. 966. 元音拼写检查器
  17. cocosbuilder创建工程
  18. cmd 更新 pip版本指令
  19. aiem模型matlab,基于MIMICS模型的麦田地表土壤含水量反演研究
  20. Laravel 使用视图合成器 view composer 实现视图变量共享

热门文章

  1. 机器人总动员主角简笔画_机器人总动员人物简介
  2. 思科AP修改AP位置描述通过WLC命令方式
  3. 逆战选择服务器后显示器,逆战游戏设置知识_隐藏在数据设置背后的大学问_叶子猪逆战...
  4. LiveNVR监控流媒体Onvif/RTSP常见问题-接入的通道没有云台控制按钮云台控制灰色无法操作怎么办?
  5. VLAN作用、超级vlan、转发、网课
  6. TCP协议为什么是三次握手而不是两次
  7. 性格与领导力 ——不可不知的DISC 性格学
  8. Java读取excel指定行列的数据(poi的方式)
  9. C# sha256和HmacSHA256加密
  10. Windows任务管理器,远比你想象中的复杂