Hive SQL必刷练习题:连续问题 & 间断连续

问题描述:

1) 连续问题:找出连续三天(或者连续几天的啥啥啥)。

2) 间断连续:统计各用户连续登录最长天数,间断一天也算连续,比如1、3、4、6也算登陆了6天

问题分析:

这两类问题,都是涉及到连续,只不过连续类问题只要判断出来相邻的时间是和当前行的时间挨着即可,而间断连续,是还可能在期间有中断现象,并且即使中断了,也要算在连续的时间内,比如1、3、4、6号登录,但是算是连续登陆了6天。所以只要中断不超过两天,也能判断出来是连续的,并且在计算连续天数的时候还要算上这个时间。

解决思路:

1)针对连续问题:

可以通过对每一个用户id进行开窗,然后排序里面的时间,加上row_number(),这样对每一个日期都会有一个排序,之后将日期减去排序序号,只要这个值是一样的,就说明这几天是连续的。之后只要根据用户id,以及这个减去过排序序号的差值diff进行一起group by分组,然后通过having count(*) >= 3,这个筛选条件过滤出的结果就是最终连续登录了三天的用户

2)针对间断连续问题:

​ 也是对每一个用户id进行开窗,只不过这次是针对当前行,用lag()取上一行数据。【必须要看上一行,而不是看下一行,因为如果当前行开始变化,当前行需要记录,如果看下一行,那看的是下一行有没有变化,是不是不连续了之类的,下一行的情况无法记录】。之后用当天日期对这个用开窗函数得到的上一天日期进行相减,如果大于2,就说明相邻两天的日期是超过了2天,按照定义不算是"连续",所以增加个标记,记录为1,这样每一行都会有一个标记,如果是连续的,那这一行后面就标记的0

​ 接下来就是关键的步骤,根据**用户id进行开窗求sum聚合group by,然后从最开始的一行,到当前行,进行求sum。**这样的话,原本是1、0、0、1、0、1、0,比如是这样的标记序列,每到一个1就说明从这天开始,就不是间断一天连续了,然后从最开始一行到当前行求sum的结果就是,1、1、1、2、2、3、3。这就很好的划分出来三段"间断连续时间"。

​ 然后根据用户id,以及这个标记进行分组聚合group by,求出来这个期间日期的max,以及日期的min,相减,别忘了再加1【日期计算时候需要注意的】,就是这个间断连续的天数了。

总结:

​ 所以总的来说,要么就是用开窗函数对日期进行排序,然后当前日期减去排序序号,去看日期一样的就是连续操作的记录

​ 当然,如果想用统计间断连续的方法去看连续n天的问题,也可以,就是取一个lag(),或者取一个lead(),进行开窗,不用加标记,直接一个where过滤diff=2,这就是统计连续3天的用户,不过同一个用户可能会有多个这个符合条件的,最后需要去重count(distinct(user_id)) 。如果是为了找到连续3天登录过的用户

​ 要么就是利用开窗函数取得上一行lag()日期,两个日期相减,去判断是否符合条件,接下来加一个标记,不符合的设为1,用作记录改变的时间点,其余标0。然后开窗函数对标记进行求和,是从第一条到当前条,这样就可以看出来一个用户id,划分了几个连续时间段,然后再根据需求去具体的求。

然后上代码:

1) 连续:

sql 复制代码
seleet id
from (
	select
		id,
		dt,
		date_sub(dt, row _number( over(partition by id order by dt) rk) as diff
	from (
		select 
			id, 
			dt, 
			sum(lowcarbon) lowcarbon
		from testl
		group by id, dt
		having lowcarbon >100
	) t1
) t2
group by id, diff
having count(*) >= 3

2) 间断连续

select
    user_id,
    max(recent_days) max_recent_days  --求出每个用户最大的连续天数
from
(
    select
        user_id,
        user_flag,
        datediff(max(login_date),min(login_date)) + 1 recent_days --按照分组求每个用户每次连续的天数(记得加1)
    from
    (
        select
            user_id,
            login_date,
            lag1_date,
            concat(user_id,'_',flag) user_flag --拼接用户和标签分组
        from
        (
            select
                user_id,
                login_date,
                lag1_date,
                sum(if(datediff(login_date,lag1_date)>2,1,0)) over(partition by user_id order by login_date) flag  --获取大于2的标签
            from
            (
                select
                    user_id,
                    login_date,
                    lag(login_date,1,'1970-01-01') over(partition by user_id order by login_date) lag1_date  --获取上一次登录日期
                from
                (
                    select
                        user_id,
                        date_format(login_datetime,'yyyy-MM-dd') login_date
                    from login_events
                    group by user_id,date_format(login_datetime,'yyyy-MM-dd')  --按照用户和日期去重
                )t1
            )t2
        )t3
    )t4
    group by user_id,user_flag
)t5
group by user_id;
      )t2
        )t3
    )t4
    group by user_id,user_flag
)t5
group by user_id;
相关推荐
JermeryBesian34 分钟前
Flink系统知识讲解之:容错与State状态管理
java·大数据·flink
誓约酱1 小时前
Linux下ext2文件系统
android·linux·c语言·数据库·c++·后端·ubuntu
橘子师兄1 小时前
mysql本地安装和pycharm链接数据库操作
数据库·mysql·pycharm
云道轩1 小时前
openGauss 创建数据库
数据库·sql·oracle
狮歌~资深攻城狮2 小时前
什么是数据仓库?
数据仓库
秋夜白2 小时前
【LevelDB 和 Sqlite】
数据库·sqlite
无奈ieq2 小时前
spark汇总
大数据·分布式·spark
weixin_307779132 小时前
理解Spark中运行程序时数据被分区的过程
大数据·分布式·spark
viperrrrrrrrrr72 小时前
大数据学习(33)-spark-transformation算子
大数据·hive·学习·spark·mapreduce
zfj3212 小时前
学英语学Elasticsearch:04 Elastic integrations 工具箱实现对第三方数据源的采集、存储、可视化,开箱即用
大数据·elasticsearch·搜索引擎·logstash·elastic agent·与第三方集成