题解 | #2021年11月每天新用户的次日留存率#
2021年11月每天新用户的次日留存率
http://www.nowcoder.com/practice/1fc0e75f07434ef5ba4f1fb2aa83a450
通过代码
select
a.dt,
round(count(distinct b.uid)/count(a.uid),2) uv_left_rate
from (select
uid,
min(date(in_time)) dt
from
tb_user_log
group by
uid) a
left join (
select
uid ,
date(in_time) dt
from
tb_user_log
union
select
uid ,
date(out_time) dt
from
tb_user_log) b
on
a.uid = b.uid
and
a.dt = date_sub(b.dt, INTERVAL 1 day)
where
date_format(a.dt,'%Y-%m') = '2021-11'
group by
a.dt
order by
a.dt;
思路
统计2021年11月每天新用户的次日留存率(保留2位小数)
注:
次日留存率为当天新增的用户数中第二天又活跃了的用户数占比。
如果in_time-进入时间和out_time-离开时间跨天了,在两天里都记为该用户活跃过,结果按日期升序。
那么问题来了,我们需要怎样的一张表来算出结果呢?
就是所有用户第一天上号的日期,以及对应的第二天日期这个人上号没,这个人的其他天数据没有用!
然后我们以用户第一天上号日期为组,计算当天人头数 / 后边对应第二天人头数就是留存率。
好了,我们的需求已经知道了,
用户第一天上号日期好办,直接min就是第一次出现在表中的时间
表1.
select
uid,
min(date(in_time)) dt
from
tb_user_log
group by
uid
怎么知道对应的第二天该用户上号没呢?
我们把这个人所有的上号记录找出来,与表1进行以表1为主表的外连接,筛选条件就是有第二天上号的记录没 连接之后,如果有就能count到,如果没有就是null,count会自动忽略。
然后题上说了
如果in_time-进入时间和out_time-离开时间跨天了,在两天里都记为该用户活跃过
这个条件怎么达成呢?
我们直接进行union
把in_time,out_itme union入同一列
因为union会自动过滤重复行
也就是说如果一个人是在今天in,但是在明天out,在这个新生成的上号表里就会有两条记录
表2.
select
uid ,
date(in_time) dt
from
tb_user_log
union
select
uid ,
date(out_time) dt
from
tb_user_log
我们用date_sub来计算差一的日期,也就是说表1 表2 连接条件是
a.uid = b.uid and a.dt = date_sub(b.dt, INTERVAL 1 day)
哦对了,最后别忘了count计算的时候要保留两位小数,还有筛选日期是2021年11月,以及最后的日期升序。
一天一个Mysql 文章被收录于专栏
学习,一天一个mysql