SQL<2021年11月每天新用户的次日留存率>的两种解法
问题
题目:统计2021年11月每天新用户的次日留存率(保留2位小数)
https://www.nowcoder.com/share/jump/7965046151741018052948
特殊限制:
- 2021年11月 A
- 每天新用户 B
- 保留两位小数 C
- 跨天标记活跃 D
- 结果日期升序 E
- 无新用户不输出 F
解法A
- 每天新增的用户首次和下次的日期记录。输出首次、下次用户记录。sub1 A
取最小范围数,可以用rank、group by?链接
通过排序窗口函数,筛选num<=2。 - 判断当天新增用户的次日是否留存。输出首日、是否留存。sub2 B、D(在上个步骤也输出out_time,比较in_time和out_time判断跨日)
通过date_add判断,标记if_stay - 计算每日新增用户的留存率。C、E、F
按date group by,计算留存率。
select
date_in_time dt,
round(sum(if_stay)/count(*),2) v_left_rate
from(
select
uid,
date_in_time,
case when
lead(date_in_time)over(partition by uid order by date_in_time)=date_add(date_in_time,interval 1 day)
or date_out_time=date_add(date_in_time,interval 1 day)
then 1
else 0
end if_stay,
num
from (
select
distinct
uid,
date(in_time) date_in_time,
date(out_time) date_out_time,
dense_rank()over(partition by uid order by date(in_time)) num
from tb_user_log
)sub1
where year(date_in_time)=2021 and month(date_in_time)=11 and num<=2
order by date_in_time
) sub2
where num=1
group by date_in_time
having count(*)<>0
order by date_in_time
解法B
- UNION联合活跃日(包括in_time日与out_time跨日)D
- 找出新用户首日。
- Left Join连接表,and条件筛选留存。得到首日、活跃日的联合数据,将首日除以活跃日,得到次日活跃度。A、B、C、E、F
select
earliest_date,
round(count(active_date)/count(earliest_date),2) uv_left_rate
from (
select
uid,
min(date(in_time)) earliest_date
from tb_user_log
group by uid
) earliest
left join(
select
uid,
date(in_time) active_date
from tb_user_log
union
select
uid,
date(out_time)
from tb_user_log active_date
) active
on earliest.uid=active.uid
and active.active_date=date_add(earliest.earliest_date,interval 1 day)
where month(earliest.earliest_date)=11
group by earliest_date
区别
解法A的视角是「用户的下一次行为是否满足次日留存」,属于「从用户行为序列中找规律」。
解法B的视角是「用户的活跃日期是否包含次日的记录」,通过 LEFT JOIN 将用户首日与次日活跃日期关联,属于「从日期维度反向匹配」。