SQL连续问题

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

用户连续登录天数

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

《SQL连续问题》

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

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

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

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

《SQL连续问题》

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

《SQL连续问题》

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

《SQL连续问题》

这样,我们根据排序的序号,就可以将间隔天数为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;

《SQL连续问题》

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

2.根据登录日期排序

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

《SQL连续问题》

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

后记

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

    原文作者:橘猫吃不胖
    原文地址: https://www.jianshu.com/p/1f0547c8ff18
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞