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;
相关推荐
福娃筱欢1 分钟前
Oracle迁移KES提示ERROR: type “geometry“ does not exist
数据库·oracle
mldlds4 分钟前
使用 Qt 插件和 SQLCipher 实现 SQLite 数据库加密与解密
数据库·qt·sqlite
大空大地20268 分钟前
Entity Framework
数据库
王仲肖13 分钟前
PostgreSQL 事务 ID 年龄增长与冻结机制分析
数据库·postgresql
AI营销先锋13 分钟前
AI营销SaaS榜单评测:原圈科技如何助力品牌客户破局增长?
大数据·人工智能
第二只羽毛16 分钟前
第六章 图
大数据·数据结构·算法·深度优先·图论·广度优先·宽度优先
好家伙VCC19 分钟前
**CQRS模式实战:用Go语言构建高并发读写分离架构**在现代分布式系统中,随着业务复杂度的提升和用户量的增长,传统的单数据库模型逐
java·数据库·python·架构·golang
不剪发的Tony老师26 分钟前
pgmetrics:一款免费开源的PostgreSQL统计指标采集工具
数据库·postgresql
@insist12327 分钟前
数据库系统工程师-必知的系统开发知识
数据库·oracle·软考·数据库系统工程师·软件水平考试
星辰_mya28 分钟前
数据库运维与数据安全:备份恢复、日志分析与故障排查
运维·数据库·后端·面试·架构师