我有一个表A_DailyLogins
,其中包含列ID
(自动递增)、Key
(用户标识)和Date
(时间戳)。我想要一个查询,它会根据 Key
从那些时间戳中返回最后连续天数,例如,如果他有昨天的一行,两天前的一行和三天前的另一行, 但最后一个不是四天前的,它会返回 3,因为这是用户最后登录的天数。
我的尝试是创建一个查询,选择按 Date
DESC 排序的球员的最后 7 行(这是我最初想要的,但后来我认为这会很棒有所有最后连续的天数),然后我检索查询结果并比较日期(使用该语言[Pawn]的函数转换为年/月/日)并增加一个日期在另一个日期之前的连续天数一天一次。 (但与我认为只能用 MySQL 直接完成的相比,这是非常慢的)
我找到的最接近的是:Check for x consecutive days - given timestamps in database .但这仍然不是我想要的样子,它仍然很不一样。我尝试修改它,但这对我来说太难了,我在 MySQL 方面没有那么多经验。
最佳答案
上下文
设consecutive login period
是用户在所有天都登录的时间段(在期间的每一天在 A_DailyLogins 中都有一个条目)在 A_DailyLogins 之前或之后没有条目同一用户的连续登录时间
和number of consecutive days
是consecutive login period
consecutive login period
的最大日期之后(连续)没有登录条目..
连续登录期
的最短日期之前(顺序)没有登录条目..
计划
- left join
A_DailyLogins
to itself using same user and sequential dates where right is null to find maximums- analogous logic to find minimums
- calculate row ordering over minimums and maximums with appropriate order by
- join maximums and minimums on row number
- filter where maximum login is yesterday/today
- calculate date_diff between maximum and minimum in range
- left join users to above resultset and coalesce over the case where user does not have a
consecutive login period
ending yesterday/today
输入
+----+------+------------+
| 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 运行
关于mysql - 从时间戳中选择最后连续的天数(今天除外),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31755051/