mysql 用户留存率计算(每日新增DNU,次日留存率,3日留存率,7日留存率)

mysql 用户留存率计算(每日新增DNU,次日留存率,3日留存率,7日留存率)我是先学习了这位大神留存率的写法 然后我自己完善了一下 阿柯 首先声明一下留存的概念次日留存 1 月 1 日注册的新用户 在 1 月 2 日登陆了 app 即登陆日期 注册日期 1 天 3 日留存 1 月 1 日注册的新用户 在 1 月 3 日登陆了 app 即登陆日期 注册日期 2 天 7 日留存 1 月 1 日注册的新用户 在 1 月 8 日登陆了 app 即登陆日期 注册日期 6 天 但是目前不同公司对留存的定义不太一样 所以以具体的规则为准 这里只是为了方便大家理解 表 user infor 包含 user id 用户

  1. 次日留存:1月1日注册的新用户,在1月2日登陆了app。即登陆日期 – 注册日期 = 1天。
  2. 3日留存:1月1日注册的新用户,在1月3日登陆了app。即登陆日期 – 注册日期 = 2天。
  3. 7日留存:1月1日注册的新用户,在1月8日登陆了app。即登陆日期 – 注册日期 = 6天。
  4. 但是目前不同公司对留存的定义不太一样,所以以具体的规则为准,这里只是为了方便大家理解。

user_infor,包含user_id(用户ID)和reg_time(注册日期)的字段。

用户ID 注册时间
user_id reg_time

login_log,包含user_id(用户ID)和login_time(登录时间

用户ID 登录时间
user_id login_time

2张表的时间都是datetime类型 YYYY-MM-DD HH:MM:SS

首先在navicate中新建2张表,建表是从大神那里复制过来的。

-- 用户注册表 create table user_info(user_id varchar(10) primary key,reg_time datetime); insert into user_info values ('u_01','2020-01-01 09:15:00'), ('u_02','2020-01-01 00:04:00'), ('u_03','2020-01-01 22:16:00'), ('u_04','2020-01-01 20:32:00'), ('u_05','2020-01-01 13:59:00'), ('u_06','2020-01-01 21:28:00'), ('u_07','2020-01-01 14:03:00'), ('u_08','2020-01-01 11:00:00'), ('u_09','2020-01-01 23:57:00'), ('u_10','2020-01-01 04:46:00'), ('u_11','2020-01-02 14:21:00'), ('u_12','2020-01-02 11:15:00'), ('u_13','2020-01-02 07:26:00'), ('u_14','2020-01-02 10:34:00'), ('u_15','2020-01-02 08:22:00'), ('u_16','2020-01-02 14:23:00'), ('u_17','2020-01-03 09:20:00'), ('u_18','2020-01-03 11:21:00'), ('u_19','2020-01-03 12:17:00'), ('u_20','2020-01-03 15:26:00'); -- 登陆日志表 create table login_log(user_id varchar(10),login_time datetime,primary key(user_id,login_time)); insert into login_log values ('u_02','2020-01-02 00:14:00'), ('u_10','2020-01-02 08:32:00'), ('u_03','2020-01-02 09:20:00'), ('u_08','2020-01-02 10:07:00'), ('u_04','2020-01-02 10:29:00'), ('u_09','2020-01-02 11:45:00'), ('u_05','2020-01-02 12:19:00'), ('u_01','2020-01-02 14:29:00'), ('u_15','2020-01-03 00:26:00'), ('u_14','2020-01-03 11:18:00'), ('u_11','2020-01-03 13:18:00'), ('u_16','2020-01-03 14:33:00'), ('u_06','2020-01-04 07:51:00'), ('u_18','2020-01-04 08:11:00'), ('u_07','2020-01-04 09:27:00'), ('u_10','2020-01-04 10:59:00'), ('u_20','2020-01-04 11:51:00'), ('u_03','2020-01-04 12:37:00'), ('u_17','2020-01-04 15:07:00'), ('u_08','2020-01-04 16:35:00'), ('u_01','2020-01-04 19:29:00'), ('u_14','2020-01-05 08:03:00'), ('u_12','2020-01-05 10:27:00'), ('u_15','2020-01-05 16:33:00'), ('u_19','2020-01-06 09:03:00'), ('u_20','2020-01-06 15:26:00'), ('u_04','2020-01-08 11:03:00'), ('u_05','2020-01-08 12:54:00'), ('u_06','2020-01-08 19:22:00'), ('u_13','2020-01-09 10:20:00'), ('u_15','2020-01-09 16:40:00'), ('u_18','2020-01-10 21:34:00'); 

首先同步一下自己学习后的思路

  1. 把user_info的新增用户表作为左表
  2. 把login_log的登录表作为链接表
  3. 使用user_id将两个表做连接,这样每个用户第一次注册的记录就可以和用户以后的所有登录数据进行匹配上
  4. 这样就先形成了一个大表
    from user_info left join login_log on user_info.user_id = login_log.user_id

  5. 在大表的基础按照用户的注册日期进行分组
    group by date(user_info.reg_time)

  6. 这样同一天注册的用户被分在同一个组里面了
  7. 首先对每日新增的用户(左表中)进行计数,由于存在重复的数据所有要去重count(distinct user_info.user_id),这样就得到了每天的新增用户数。
  8. 使用sum(datediff(login_time, reg_time) = 1) as ‘次日留存用户数’ 来分别求的其他几个纬度的用户留存情况。
  9. 这里声明一下,为什么用sum()而非count()。sum(条件表达式),如果记录满足条件表达式就加1,统计满足条件的行数。 COUNT(条件表达式),不管记录是否满足条件表达式,只要非NULL就加1。所以如果用count将计算所有的行数而非指定条件的行数。
  10. 留存率就是将n日用户留存数量 / 对应日期的新增用户数即可

最后的代码就是,我从大神那里复制来的。

select date(reg_time) dt, count(distinct user_info.user_id) 新增用户数, sum(datediff(login_time,reg_time)=1) 次日留存用户数, sum(datediff(login_time,reg_time)=3) 三日留存用户数, sum(datediff(login_time,reg_time)=7) 七日留存用户数, sum(datediff(login_time,reg_time)=1)/count(distinct user_info.user_id) 次日留存率, sum(datediff(login_time,reg_time)=3)/count(distinct user_info.user_id) 三日留存率, sum(datediff(login_time,reg_time)=7)/count(distinct user_info.user_id) 七日留存率 from user_info left join login_log on user_info.user_id=login_log.user_id group by date(reg_time); +------------+------------+----------------+----------------+----------------+------------+------------+------------+ | dt | 新增用户数 | 次日留存用户数 | 三日留存用户数 | 七日留存用户数 | 次日留存率 | 三日留存率 | 七日留存率 | +------------+------------+----------------+----------------+----------------+------------+------------+------------+ | 2020-01-01 | 10 | 8 | 6 | 3 | 0.8000 | 0.6000 | 0.3000 | | 2020-01-02 | 6 | 4 | 3 | 2 | 0.6667 | 0.5000 | 0.3333 | | 2020-01-03 | 4 | 3 | 2 | 1 | 0.7500 | 0.5000 | 0.2500 | +------------+------------+----------------+----------------+----------------+------------+------------+------------+ 

我使用concat()与round()函数进行了简单的加工

concat(round(SUM(DATEDIFF(login_time, reg_time) = 1) / COUNT(DISTINCT user_info.user_id) * 100, 1), '%') AS '次日留存率', concat(round(SUM(DATEDIFF(login_time, reg_time) = 7) / COUNT(DISTINCT user_info.user_id) * 100, 0), '%')AS '三日留存率', concat(round(SUM(DATEDIFF(login_time, reg_time) = 7) / COUNT(DISTINCT user_info.user_id) * 100, 0), '%')AS '7日留存率' 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/214639.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午3:47
下一篇 2026年3月18日 下午3:47


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号