题解 | #2021年11月每天新用户的次日留存率#

2021年11月每天新用户的次日留存率

https://www.nowcoder.com/practice/1fc0e75f07434ef5ba4f1fb2aa83a450

# 将进入和离开时间格式化,然后像上一题那样提取组合,再去重,因为只涉及两天跨天的情况,所以这样就能得到每个用户的活跃日期
# 然后在每个用户维度使用lag/lead函数判断有没有在第二天又活跃
# 根据时间排序。新增一列是每个用户最开始活跃日期
# 如果开始日期和下一个日期都存在,并且开始日期等于首次活跃日期,那就说明新用户次日留存了,设为1,否则为0,还有再设一列是新用户登录记录
# 两列聚合后相除

# 创建临时表
WITH temp_0 AS(
	# 查询uid,开始日期,
	# 使用LEAD开窗函数针对每个用户分页,使用日期正序,得到开始日期的下一个日期,
	# 使用MIN开窗聚合函数,同样的分页和排序,得到每个用户的初始活跃日期
    SELECT uid, act_date, LEAD(act_date, 1) OVER(PARTITION BY uid ORDER BY act_date) next_date, MIN(act_date) OVER(PARTITION BY uid ORDER BY act_date) uf_date
    FROM( # 子查询,查询uid,格式化的开始日期和离开日期组合并集(自动去重)
		# 这里不能用上一题的文章id筛选,因为只要有记录那用户一定登录活跃了
        SELECT uid,	DATE_FORMAT(in_time, '%Y-%m-%d') act_date
        FROM tb_user_log
        UNION # 自动去重
        SELECT uid,	DATE_FORMAT(out_time, '%Y-%m-%d') act_date
        FROM tb_user_log
        ) a # 每个子查询作为表必须要设置别名
    # 不能加在这,因为有用户十月份就进来。加这的话就意味着系统十一月才上线
    # WHERE act_date BETWEEN '2021-11-01' AND '2021-11-30'
    )

SELECT act_date, ROUND(SUM(su_c)/SUM(uf_c), 2) uv_left_rate
FROM( # 子查询,查询uid,开始日期
		# 判断是否次日成功留存,是就是1,不是就是0
		# 判断是否是当日新增活跃的,1,0
    SELECT uid, act_date, 
            CASE WHEN act_date IS NOT NULL AND next_date  IS NOT NULL AND act_date = uf_date THEN 1 ELSE 0 END su_c,
            CASE WHEN act_date IS NOT NULL AND act_date = uf_date THEN 1 ELSE 0 END uf_c
    FROM temp_0
    ) a # 别名是局部变量,实际似乎也没用到,跟上面取一样也行
# 限制日期
WHERE act_date BETWEEN '2021-11-01' AND '2021-11-30'
GROUP BY act_date
# 限制一天是否有新增活跃
HAVING SUM(uf_c) != 0
ORDER BY act_date

踩的坑:没有设置好在哪限制日期,应该在最后,理由见21行

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务