使用MySQL 5.7版本统计 玩家连续登录天数
原始数据
玩家同一天多次登录只保留一条
select DISTINCT(FROM_UNIXTIME(login_time,'%Y-%m-%d')) as login_date,rid from t_log_login order by rid;
借助两个变量统计每个玩家登录日期对应的次数
SELECT
*
FROM(SELECT DISTINCT FROM_UNIXTIME(login_time, '%Y-%m-%d') AS login_date,rid FROM t_log_login ) AS a,
(select @last_rid := '',@rn:=0) as b order by rid,login_date;
原始表多了两个表量,一个记录 当前循环的rid,一个记录rid出现的次数。
目前两个值都为初始值,现在对其进行调整
SELECTa.login_date,CASE
WHEN rid = @last_rid THEN@rn := @rn + 1
ELSE@rn := 1
END AS rnn,@last_rid := rid AS rid
FROM(SELECT DISTINCTFROM_UNIXTIME(login_time, '%Y-%m-%d') AS login_date,ridFROMt_log_login) AS a,(SELECT @last_rid := '' ,@rn := 0) AS b
ORDER BYrid,login_date;
我们只关注select 和from之前的字段部分,大概意思就是,如果rid等于设置的变量@last_rid ,rid对应的次数就加1,否则就等于1,然后再把rid的值赋值给 @last_rid 。可能这里不太懂,我们一步一步来看。
因此这里就体现了排序的重要性了。rid相同的必须连接在一起。
最终结果是:
使用日期函数date_add处理数据
上面的数据只能显示了每个玩家,某天对应的连续登录的第n次,中间断开的没有。比如
rid | date | rn |
---|---|---|
12345678 | 2022-10-12 | 1 |
12345678 | 2022-10-13 | 2 |
12345678 | 2022-10-14 | 3 |
12345678 | 2022-10-16 | 4 |
那只能说rid=12345678 连续登录了3天。
那这种思路是什么呢,我们用当天日期减去对应的第n天,在这个列表里面也就是,2022-10-12 减去 1 天,也就是 2022-10-11 , 2022-10-13 号减去两天也是 2022-10-11 , 依次类推,因为 rn是顺序加1的,因此只要保证 日期也是顺序 加 1 的,就能说用户是连续登录了的。
因此思路:看 date - rn 对应日期 出现 的次数 就是 连续登录的天数了。就用group by就行了。
最终SQL:
select rid,count(*) as login_counts from(SELECTa.login_date,CASE
WHEN rid = @last_rid THEN@rn := @rn + 1
ELSE@rn := 1
END AS rnn,@last_rid := rid AS rid
FROM(SELECT DISTINCTFROM_UNIXTIME(login_time, '%Y-%m-%d') AS login_date,ridFROMt_log_login) AS a,(SELECT @last_rid := '' ,@rn := 0) AS b
ORDER BYrid,login_date
)as d group by rid,date_add(d.login_date,interval -@rn day) ;
思考
以上的sql可能出现表述不清楚的问题,如果是这种情况
rid | date | rn |
---|---|---|
12345678 | 2022-10-12 | 1 |
12345678 | 2022-10-13 | 2 |
12345678 | 2022-10-14 | 3 |
12345678 | 2022-10-16 | 4 |
12345678 | 2022-10-17 | 5 |
那么 12345678 就会出现两行,因此要加上一个开始时间从哪天开始连续登录的。
select rid,
date_add(d.login_date,interval -@rn day) as login_start_before,
count(*) as login_counts from(SELECTa.login_date,CASE
WHEN rid = @last_rid THEN@rn := @rn + 1
ELSE@rn := 1
END AS rnn,@last_rid := rid AS rid
FROM(SELECT DISTINCTFROM_UNIXTIME(login_time, '%Y-%m-%d') AS login_date,ridFROMt_log_login) AS a,(SELECT @last_rid := '' ,@rn := 0) AS b
ORDER BYrid,login_date
)as d group by rid,login_start_before ;
注意这里 开始时间需要在加上 一天,因为我们算的 日期 - 第n次出现,得到的是首次登录的前一天。这里就自己在外层加个日期转换就行了哦。