I have a table A_DailyLogins
with the columns ID
(auto increment), Key
(userid) and Date
(timestamp). I want a query which would return the number of last consecutive days from those timestamp based on the Key
, for example if he has a row for yesterday, one for two days ago and another one for three days ago, but the last one isn't from four days ago, it would return 3, because this is the number of last days the user was logged in.
My attempt was to create a query selecting the last 7 rows of the players ordered by Date
DESC (this is what I wanted in the first place, but then I thought that it would be great to have all the last consecutive days), and then I retrieved the query result and compared the dates (converted to year/month/day with functions from that language [Pawn]) and increased the number of consecutive days when a date is before the other one with one day. (but this is extremely slow compared to what I think that can be done directly only with MySQL)
The closest thing I found is this: Check for x consecutive days - given timestamps in database . But it still isn't how I want it to be, it's still pretty different. I tried to modify it, but it is way too hard for me, I don't have that much experience in MySQL.
答案 0 :(得分:1)
<强>上下文强>
让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 强>