首日次日留存率:AVG 一个布尔值
LeetCode 550 · 次日留存、LEFT JOIN、条件求平均
面试怎么回答
这是次日留存。先按玩家求首登日,再 LEFT JOIN 活动表找 DATEDIFF = 1 的记录,用 AVG(a.event_date IS NOT NULL) 直接得到留存比例。LEFT JOIN 保证分母是全部玩家,布尔值求平均等于命中数除以总数。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
题意
计算「首次登录后第二天又登录了」的玩家,占全部玩家的比例,保留两位小数。
表结构
- Activity:player_id、device_id、event_date、games_played;(player_id, event_date) 为主键
思路
先求每个玩家的首次登录日期,再用 LEFT JOIN 去找「首日 + 1 天」的登录记录:找得到的玩家留存了,找不到的那一列为 NULL。对「是否找得到」这个布尔值求平均,就是留存玩家数 / 总玩家数,一步出比例。
参考解法
select round(avg(a.event_date is not null), 2) fraction
from
(select player_id, min(event_date) as login
from activity
group by player_id) p
left join activity a
on p.player_id=a.player_id and datediff(a.event_date, p.login)=1
易错点
- 用 INNER JOIN 会把没留存的玩家丢掉,分母变小。
- 题目要的是首日的次日,不是任意相邻两天都登录。