代码及说明
使用with..as..语句计算留存率,可以提高计算的复用率,A1,A2两个表完全可以相同,分开是因为可以设置不同的活跃和留存事件,否则可以进一步简化。还有用户的统计口径,这里用client_id,可以替换为user_id以及client_id+user_id。
A1,A2取出时间范围内每个用户的活跃天数,B1计算出A1中各个用户在哪几天产生留存(retention)事件。C1再根据日期和留存天数算出留存用户数。其实大部分场景下到这里就可以结束了,剩下的计算可以由后续的数据可视化工具来完成。但是因为我用的QuickBI没有这么灵活的操作,于是C2从C1提取0日数据做为日活,直接在模型中计算出留存率。
BI上用这个表结构,把dt放在列,把day_of_retention作为行,再把需要的指标放进去即可实现梯形视图下的留存率表格。
WITH
A1 AS (
-- 初始行为
SELECT dt,
client_id
FROM ods_user_behavior_fixed
WHERE dt >= '${report_date_ph.get(0)}'
AND dt <= '${report_date_ph.get(1)}'
AND client_id != ''
AND event = 'display'
GROUP BY dt, client_id
),
A2 AS (
-- 后续行为
SELECT dt,
client_id
FROM ods_user_behavior_fixed
WHERE dt >= '${report_date_ph.get(0)}'
AND dt <= '${report_date_ph.get(1)}'
AND client_id != ''
AND event = 'display'
GROUP BY dt, client_id
),
B1 AS (
-- 时间段内每个用户的留存天数
SELECT A1.client_id,
A1.dt,
DATEDIFF(TO_DATE(A2.dt, 'yyyymmdd'), TO_DATE(A1.dt, 'yyyymmdd'), 'dd') AS day_of_retention
FROM A1 INNER JOIN A2 ON A1.client_id = A2.client_id AND A1.dt <= A2.dt
),
C1 AS (
-- 每个初始日期,每个留存日的留存人数
SELECT dt,
day_of_retention,
COUNT(distinct client_id) AS cnt
FROM B1
GROUP BY dt, day_of_retention
),
C2 AS (
-- 0日留存等于日活
SELECT *
FROM C1
WHERE day_of_retention = 0
)
SELECT C1.dt,
C1.day_of_retention,
C2.cnt AS dau,
C1.cnt AS retentions,
C1.cnt / C2.cnt AS retention_rate
FROM C1
LEFT JOIN C2
ON C1.dt = C2.dt
ORDER BY C1.dt, C1.day_of_retention
LIMIT 10000;
TODO
关于梯形视图,梯形视图是因为这个表格通常用来看最近的n天数据,但是时间越靠近今天缺失的数据就越多。比如T-1日,他一定不会有次日留存,T-2日一定不会有三日留存,所以产生了梯形。可是如果这个时间再整体往前推n天,那么所有的日期都应该有n日留存,那就可以不是梯形了,但是这个例子还是会输出梯形,你可以通过修改A2的dt范围条件来实现这个更好的体验。