上下文
让consecutive login period 成为用户全天登录的时段(在 A_DailyLogins 中的每一天都有一个条目),其中在 consecutive login period 之前或之后的 A_DailyLogins 中没有相同用户的条目
和number of consecutive days 是consecutive login period 中最大和最小日期之间的差
consecutive login period 的最大日期紧随其后(顺序)没有登录条目..
consecutive login period 的最短日期之前(按顺序)没有登录条目。
计划
- 使用相同的用户和连续日期将
A_DailyLogins 左连接到自身,其中右为空以查找最大值
- 寻找最小值的类比逻辑
- 使用适当的顺序计算最小和最大的行排序
- 加入行号的最大值和最小值
- 过滤昨天/今天的最大登录次数
- 计算范围内最大值和最小值之间的 date_diff
- 将用户左连接到上述结果集,并在用户没有
consecutive login period 昨天/今天结束的情况下合并
输入
+----+------+------------+
| ID | Key | Date |
+----+------+------------+
| 25 | eric | 2015-12-23 |
| 26 | eric | 2015-12-25 |
| 27 | eric | 2015-12-26 |
| 28 | eric | 2015-12-27 |
| 29 | eric | 2016-01-01 |
| 30 | eric | 2016-01-02 |
| 31 | eric | 2016-01-03 |
| 32 | nusa | 2015-12-27 |
| 33 | nusa | 2015-12-29 |
+----+------+------------+
查询
select all_users.`Key`,
coalesce(nconsecutive, 0) as nconsecutive
from
(
select distinct `Key`
from A_DailyLogins
) all_users
left join
(
select
lower_login_bounds.`Key`,
lower_login_bounds.`Date` as from_login,
upper_login_bounds.`Date` as to_login,
1 + datediff(least(upper_login_bounds.`Date`, date_sub(current_date, interval 1 day))
, lower_login_bounds.`Date`) as nconsecutive
from
(
select curr_login.`Key`, curr_login.`Date`, @rn1 := @rn1 + 1 as row_number
from A_DailyLogins curr_login
left join A_DailyLogins prev_login
on curr_login.`Key` = prev_login.`Key`
and prev_login.`Date` = date_add(curr_login.`Date`, interval -1 day)
cross join ( select @rn1 := 0 ) params
where prev_login.`Date` is null
order by curr_login.`Key`, curr_login.`Date`
) lower_login_bounds
inner join
(
select curr_login.`Key`, curr_login.`Date`, @rn2 := @rn2 + 1 as row_number
from A_DailyLogins curr_login
left join A_DailyLogins next_login
on curr_login.`Key` = next_login.`Key`
and next_login.`Date` = date_add(curr_login.`Date`, interval 1 day)
cross join ( select @rn2 := 0 ) params
where next_login.`Date` is null
order by curr_login.`Key`, curr_login.`Date`
) upper_login_bounds
on lower_login_bounds.row_number = upper_login_bounds.row_number
where upper_login_bounds.`Date` >= date_sub(current_date, interval 1 day)
and lower_login_bounds.`Date` < current_date
) last_consecutive
on all_users.`Key` = last_consecutive.`Key`
;
输出
+------+------------------+
| Key | last_consecutive |
+------+------------------+
| eric | 2 |
| nusa | 0 |
+------+------------------+
有效期为 2016-01-03
sqlfiddle