首先声明一下留存的概念

  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日留存率'

这样就行变为百分数的形式了

mysql实现留存率计算 mysql次日留存率_链接表