通过真实业务数据,练习产品分析 SQL。
SQL 课程 20:用户留存分析
留存分析关注的不是“来了多少人”,而是“第一次来过的人,之后还有没有回来”。例如某个月第一次跟进的客户,后续月份是否再次产生跟进记录?这就是一个最基础的留存问题。
当前 CRM 数据没有独立的 user_id 和产品事件表,因此本课把 account(客户名称)作为用户,把 engage_date(开始跟进日期)作为行为时间。这个定义会在查询中明确写出来,避免把商机数量误当成用户数量。
我们会先找到每个客户第一次出现的月份,把它称为 cohort_month(用户群组月份);再观察同一客户在哪些月份继续出现,计算月活跃客户、群组留存数量和留存率。
WITH account_cohorts AS (
SELECT account,
MIN(strftime('%Y-%m', engage_date)) AS cohort_month
FROM sales_pipeline
GROUP BY account
), monthly_activity AS (
SELECT DISTINCT account,
strftime('%Y-%m', engage_date) AS activity_month
FROM sales_pipeline
)
SELECT ...;先说清楚:谁是用户,什么算一次行为
在真实产品事件表中,用户通常由 user_id 标识,行为可能是登录、浏览或完成任务。本课没有这样的产品事件表,所以使用 CRM 中最接近的业务对象:account 代表客户,engage_date 代表一次开始跟进行为。
这意味着本课得到的是“客户跟进留存”的练习结果,不是 App 登录留存。换成真实产品事件表时,只需要替换用户字段和行为日期,分析思路仍然相同。
SELECT strftime('%Y-%m', engage_date) AS activity_month,
COUNT(DISTINCT account) AS active_accounts
FROM sales_pipeline
WHERE account IS NOT NULL
AND engage_date IS NOT NULL
GROUP BY activity_month
ORDER BY activity_month ASC;小提醒:统计用户数量时要用 COUNT(DISTINCT account),不能直接 COUNT(*);一个客户一个月可能有多笔商机。
Cohort:把第一次出现的用户放进同一组
如果一个客户第一次在 2016-11 被跟进,就属于 2016-11 这个 cohort。之后它在 2016-12、2017-01 是否再次出现,会分别记录在对应的 activity_month 中。
monthly_activity 先用 DISTINCT 把同一个客户在同一个月份的多笔记录合并成一次“月活跃”。这样留存人数统计的是客户数,而不是商机数。
留存分析里的三个时间概念
| 字段 | 含义 | CRM 对应字段 |
|---|---|---|
| 用户 | 被观察的对象 | account 客户 |
| 首次月份 | 用户第一次出现的月份 | 最早 engage_date 的月份 |
| 活跃月份 | 用户再次出现的月份 | engage_date 所在月份 |
留存率的分母必须是最初那批用户
某个 cohort 在后续月份的留存率 = 该 cohort 在这个月份仍然活跃的客户数 ÷ 该 cohort 最初的客户数。分母不能换成当月全部活跃客户,否则算出来的是当月构成比例,不是留存率。
最后一题会计算次月留存:例如 2016-11 cohort 的客户,在 2016-12 再次出现了多少。越靠近数据末尾的 cohort,可观察的后续月份越少,这是留存分析中的常见限制。
练习
本课严格按客户去重。请先排除缺失客户和缺失日期,再区分 cohort_month、activity_month、cohort_size 与 retained_accounts。