SQL连续问题

在日常工作或者面试时,我们经常会遇到这样的问题,比如:“统计下用户最长连续登录的天数”,“统计下连续登录超过10天的用户”,“统计下连续3天交易额超过100W的店铺”。这种问题,其实都是一个套路,我们这里简单介绍一种解决思路。

用户连续登录天数

我们先来看下用户连续登录问题,我们简化下数据,只保留用户ID和登录时间:

其实做数据来说,我们的思路一定要清晰,知道我们要什么样的数据,就像这个连续问题,如果我们知道怎样来判断连续,只要再转化成SQL就行了。所以,我们先思考下,怎样来判断用户是不是连续登录。

连续其实就是这样,我今天登录了,然后昨天也登录了,说明我就连续两天登录了,我们也经常会在APP或者网站上遇到什么签到领积分,签到多少天领奖品之类的,其实都是产品为了提高日活提高用户留存的套路。

1.根据上次登录日期判断

我们回过头,继续看这个连续的问题,上面的数据已经有了,如果要手工判断用户登录是否连续的话,会怎样来呢?比如,用户今天登录了,我们只需要用户上一次登录是什么时候就可以了,如果用户昨天也登录了,就说明用户是连续登录第2天了,所以,我们将数据处理一下。

现在我们有了用户本次登录日期和上次登录日期,只要用户本次登录和上次登录的间隔天数是1,就说明用户连续登录了,我们来看看

这样,我们就可以看到,我们根据本次登录时间和上次登录时间,计算出间隔天数,间隔为1的都是连续的日期,首次登录的时候,我们可以填入默认值0。这样看上去标注黄色的都是连续的日期,但是要注意,第一个标黄的日期表示2天。那我们该怎样统计出用户每次连续的天数呢?如果只把间隔天数为1的记录拿出来,好像又没有办法统计哪些天是连续一起的,我们再对这个间隔天数做个排序


这样,我们根据排序的序号,就可以将间隔天数为1的记录拿出来聚合了。

下面我们就需要将上面的想法转化成SQL:

由于我们要使用mysql,mysql中没有开窗函数,写起来很麻烦,需要多次使用变量;

pg版可以参考之前的文章:SQL笔试题-连续登录天数

-- 1. 获取间隔天数

-- 初始化变量

set @pre_login_date:=null,@pre_user_id:=null;

drop table if exists tmp_20180415_1;

create table tmp_20180415_1 as

select

user_id,

login_date,

pre_login_date,

-- 计算本次登录和上次登录的差值

coalesce(datediff(login_date,pre_login_date),0) as diff_days

from (

select

-- 当前记录

user_id, -- 当前user_id

login_date, -- 当前login_date

-- 上一条记录

@pre_user_id as pre_user_id,

if(@pre_user_id=user_id , @pre_login_date , null) as pre_login_date,

-- 初始化上一条记录

@pre_login_date:=login_date as cur_login_date,

@pre_user_id:=user_id  as cur_user_id

from

tm_login_log

order by

user_id,login_date

) x

order by user_id,login_date;

-- 2.对间隔天数进行排序

set @pre_user_id:=null,@pre_diff_days:=0,@rn:=1;

select

user_id,rn , min(pre_login_date) as from_login_date,max(login_date) as to_login_date

from (

select

user_id,

login_date,

pre_login_date,

diff_days,

if(@pre_user_id=user_id,if(@pre_diff_days=diff_days,@rn:=@rn,@rn:=@rn+1),@rn:=1) as rn,

@pre_user_id:=user_id,

@pre_diff_days:=diff_days

from tmp_20180415_1

order by user_id,login_date

) x

where diff_days=1

group by user_id,rn;


结果时这样的,用户ID和他连续登录的日期,但是这个rn并没有什么用,如果要看连续登录天数的话,我们可以重新根据开始时间和结束时间进行计算。继续延伸的话,我们还可以统计用户最长的登录天数。


2.根据登录日期排序

还有一种类似的思路,就是首先根据登录日期排序,这样我们获得的排序序号就是连续的,然后再统计每个登录日期和一个初始日期的间隔天数,如果登录连续的话,2个值相减之后也可以用来判断是否连续。


感兴趣的同学可以试试MySQL的实现。

后记

其实大家主要了解思路就行了,使用mysql来实现,比较麻烦,不会写也没问题,当然应该还有更简便的方法,只是我还没有想到。在日常工作中,其实还有很多别的方式来更方便的实现,比如,我们可以创建一张用户每天登录的表,然后在刷新当天数据的同时,去判断昨天该用户有没有登录,有的话则计入连续;Hive中也支持各种开窗函数,写起来很简单。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容