确定一段时间内的操作 PHP MySQL
determine actions over period of time PHP MySQL
我没有任何代码或数据库可以显示,因为我正处于计划阶段,我无法找出正确的方法来执行此操作。
我想确定用户在一周内是否每天都执行了特定操作。如果他们有,我想执行一个动作。每次休息几天,我都需要重新设置。
例如:
Day 1 | task performed 25 times
Day 2 | task performed 13 times
Day 3 | task performed 18 times
Day 4 | task not performed... start over at Day 1.
.....
Day 1 | task performed 3 times
Day 2 | task performed 11 times
Day 3 | task performed 14 times
Day 4 | task performed 7 times
Day 5 | task performed 3 times
Day 6 | task performed 10 times
Day 7 | task performed 23 times
回声'You have successfully completed 71 tasks consecutively over a period of 7 days';
我想真正的问题是,实现这一目标的最佳方法是什么?我是否应该尝试根据日期存储 7 个 cookie,并在最新的 cookie 值超过 24 小时后销毁所有现有的 cookie?我应该尝试通过数据库设置和更新日期吗?
作为实现此目标的潜在解决方案的建议是我正在寻找的,请记住这是我正在开发的一个数据库密集型应用程序,因此数据库调用 IMO 越少越好。
更新
所以我正在尝试使用数据库来计划这个,我只是 运行 从各个角度处理问题。
如果我尝试设置增量列,则无法判断上次更新的时间。
如果我设置 table,它会非常复杂,因为我必须将值作为连续日期的基础。所以我不能做一个简单的 7 天搜索,我必须测试每个结果都在数据库中前一个结果集的 24 小时内,否则我怎么能区分第 1、3 天完成任务的人,和 7 对比完成它的人 1、2、3、4、5、6 和 7。
清理数据库同样麻烦。我将如何进行清理。我不能简单地测试数据是否在当前日期的 7 天内,因为这不包括某人在第 5 天完成任务但不是第 6 天......然后在第 7 天......同样它很复杂,因为每个用户都有不同的开始日期。所以我可能今天开始了任务,而另一个用户 5 天前开始了任务。我可以安全地假设所有超过 7 天的日期都已过期,但这并不能真正帮助确定天数。
我很困惑如何真正完成这项任务。
将您的数据保存在数据库中,因为 cookie 的问题是用户可以随时清理 his/her 浏览器。数据库中的数据可以随时处理。
假设您在数据库中以这种格式保存数据:
Description | task_id | created
Task perfor. | 2 | 2016-10-17
Task perfor. | 2 | 2016-10-17
Task perfor. | 2 | 2016-10-18
Task perfor. | 2 | 2016-10-18
您可以通过运行查询删除数据:
delete from table where created = date
一个查询就可以清理你的数据,一点都不乱。即使是巨大的数据库也是这样处理的。
有几种方法可以做到这一点。
如果你要使用 db 路线,你可以参考这个 SQL fiddle
我不知道它的数据库密集程度如何,但我认为如果您要走这条路,那将总结所需的工作。这条路线的优点是你不必删除或重置任何东西,所以你将拥有历史数据,例如你可以通过将上面的查询更改为 having count(distinct d) < 7
来获得用户做了多少 "tries" (它会return 用户尝试完成任务的行数)
另一种方法是您可以使用基于文件的数据,例如在服务器端为每个执行任务的用户使用 JSON 文件。使用这条路线,您需要自己维护数据,例如您有这个简单的 JSON 结构:
{
"day1": "2016-09-01",
"last_task": "2016-09-03",
"accumulated_task": "56"
}
我所说的自己维护数据的意思是,每次应用更改时都需要更新它,例如当前日期是 2016-09-05
并且 last_task
是 2016-09-03
,那么你需要重置它。这条路线的好处当然是没有db开销,但是很多"manual labor".
这将假设我们的测试页面 id = 9 ... 已查看,计入徽章(用户连续 7 天查看该页面)。这一事实已从操作评论中删除(7 天和一个徽章)。至于第 9 页,我们刚刚在此答案中进行了补充。
因此,如果用户连续 7 天查看该页面,我们希望该用户出现在输出中。注意,页码是 9.
架构和数据加载
create schema db40076704;
use db40076704;
create table pageViews
( id int auto_increment primary key,
userId int not null,
viewDT datetime not null,
pageId int not null
-- include decent index choices here
-- include Foreign Key constraints here
);
truncate pageViews;
insert pageViews (userId,viewDT,pageId) values
(101,'2016-09-05 21:00:00',9),
(101,'2016-09-06 11:00:00',9),
(101,'2016-09-06 15:55:00',9),
(101,'2016-09-06 15:57:00',9),
(101,'2016-09-07 21:00:00',9),
(101,'2016-09-08 21:00:00',999999),
(101,'2016-09-09 21:00:00',9),
(101,'2016-09-10 21:00:00',9),
(101,'2016-09-11 21:00:00',9),
(150,'2016-09-01 21:00:00',9),
(150,'2016-09-06 11:00:00',9),
(150,'2016-09-06 15:55:00',9),
(150,'2016-09-06 15:57:00',9),
(150,'2016-09-07 21:00:00',9),
(150,'2016-09-08 10:44:00',9),
(150,'2016-09-09 21:00:00',9),
(150,'2016-09-10 21:00:00',9),
(150,'2016-09-11 23:00:00',9),
(150,'2016-09-12 23:00:00',9),
(200,'2016-09-08 10:44:00',9),
(200,'2016-09-10 21:00:00',9),
(200,'2016-09-12 21:00:00',9),
(200,'2016-09-14 23:00:00',9),
(200,'2016-09-16 23:00:00',9),
(200,'2016-09-18 23:00:00',9),
(200,'2016-09-20 23:00:00',9);
显示调试详细信息的内部查询
select userId,
date(viewDT),
(@rn := if(@curUser = userId
AND (@prevDate=DATE(viewDT) OR @prevDate=DATE_SUB(DATE(viewDT),INTERVAL 1 DAY)), @rn,
if(@curUser := GREATEST(userId,-1), @rn+1, @rn+1)
)
) rn,
@prevDate:=DATE(viewDT) as dummy1
from pageViews
join (select @curUser:=-1,@prevDate:='',@rn:=0) params
where pageId=9
order by userId,viewDt;
+--------+--------------+------+------------+
| userId | date(viewDT) | rn | dummy1 |
+--------+--------------+------+------------+
| 101 | 2016-09-05 | 1 | 2016-09-05 |
| 101 | 2016-09-06 | 1 | 2016-09-06 |
| 101 | 2016-09-06 | 1 | 2016-09-06 |
| 101 | 2016-09-06 | 1 | 2016-09-06 |
| 101 | 2016-09-07 | 1 | 2016-09-07 |
| 101 | 2016-09-09 | 2 | 2016-09-09 |
| 101 | 2016-09-10 | 2 | 2016-09-10 |
| 101 | 2016-09-11 | 2 | 2016-09-11 |
| 150 | 2016-09-01 | 3 | 2016-09-01 |
| 150 | 2016-09-06 | 4 | 2016-09-06 |
| 150 | 2016-09-06 | 4 | 2016-09-06 |
| 150 | 2016-09-06 | 4 | 2016-09-06 |
| 150 | 2016-09-07 | 4 | 2016-09-07 |
| 150 | 2016-09-08 | 4 | 2016-09-08 |
| 150 | 2016-09-09 | 4 | 2016-09-09 |
| 150 | 2016-09-10 | 4 | 2016-09-10 |
| 150 | 2016-09-11 | 4 | 2016-09-11 |
| 150 | 2016-09-12 | 4 | 2016-09-12 |
| 200 | 2016-09-08 | 5 | 2016-09-08 |
| 200 | 2016-09-10 | 6 | 2016-09-10 |
| 200 | 2016-09-12 | 7 | 2016-09-12 |
| 200 | 2016-09-14 | 8 | 2016-09-14 |
| 200 | 2016-09-16 | 9 | 2016-09-16 |
| 200 | 2016-09-18 | 10 | 2016-09-18 |
| 200 | 2016-09-20 | 11 | 2016-09-20 |
+--------+--------------+------+------------+
25 rows in set (0.00 sec)
使用以上内容的最终答案
SELECT userId,rn,count(*) days_In_A_Row
from
( SELECT userId,
DATE(viewDT),
(@rn := if(@curUser = userId
AND (@prevDate=DATE(viewDT) OR @prevDate=DATE_SUB(DATE(viewDT),INTERVAL 1 DAY)), @rn,
if(@curUser := GREATEST(userId,-1), @rn+1, @rn+1)
)
) rn,
@prevDate:=DATE(viewDT) as dummy1
FROM pageViews
JOIN (SELECT @curUser:=-1,@prevDate:='',@rn:=0) params
WHERE pageId=9
ORDER BY userId,viewDt
) xDerived
GROUP BY userId,rn
HAVING days_In_A_Row>6;
+--------+------+---------------+
| userId | rn | days_In_A_Row |
+--------+------+---------------+
| 150 | 4 | 9 |
+--------+------+---------------+
所以用户 150 至少连续 7 天查看第 9 页(实际上是连续 9 天)。该用户在您的系统中获得徽章。
有关 mysql 变量(@ 变量)的一些信息。要安全地使用变量,必须注意不要假设 select 的任何输出列会先于另一列触发。这是标题为 User-Defined Variables:
的手册页中清楚说明的事实
In the following statement, you might think that MySQL will evaluate
@a first and then do an assignment second:
SELECT @a, @a:=@a+1, ...;
However, the order of evaluation for
expressions involving user variables is undefined.
也就是说,我们知道使用 GREATEST()、LEAST() 和 COALESCE() 等函数的优先级会更高。
此外,GREATEST(N,-1) 代码中的废话将始终为 return N。但是我们需要强制在
之前计算该列的优先级
@prevDate:=DATE(viewDT) as dummy1
行。另见 Baron Schwartz 的 必读 Advanced MySQL user variable techniques.
我没有任何代码或数据库可以显示,因为我正处于计划阶段,我无法找出正确的方法来执行此操作。
我想确定用户在一周内是否每天都执行了特定操作。如果他们有,我想执行一个动作。每次休息几天,我都需要重新设置。
例如:
Day 1 | task performed 25 times
Day 2 | task performed 13 times
Day 3 | task performed 18 times
Day 4 | task not performed... start over at Day 1.
.....
Day 1 | task performed 3 times
Day 2 | task performed 11 times
Day 3 | task performed 14 times
Day 4 | task performed 7 times
Day 5 | task performed 3 times
Day 6 | task performed 10 times
Day 7 | task performed 23 times
回声'You have successfully completed 71 tasks consecutively over a period of 7 days';
我想真正的问题是,实现这一目标的最佳方法是什么?我是否应该尝试根据日期存储 7 个 cookie,并在最新的 cookie 值超过 24 小时后销毁所有现有的 cookie?我应该尝试通过数据库设置和更新日期吗?
作为实现此目标的潜在解决方案的建议是我正在寻找的,请记住这是我正在开发的一个数据库密集型应用程序,因此数据库调用 IMO 越少越好。
更新
所以我正在尝试使用数据库来计划这个,我只是 运行 从各个角度处理问题。
如果我尝试设置增量列,则无法判断上次更新的时间。
如果我设置 table,它会非常复杂,因为我必须将值作为连续日期的基础。所以我不能做一个简单的 7 天搜索,我必须测试每个结果都在数据库中前一个结果集的 24 小时内,否则我怎么能区分第 1、3 天完成任务的人,和 7 对比完成它的人 1、2、3、4、5、6 和 7。
清理数据库同样麻烦。我将如何进行清理。我不能简单地测试数据是否在当前日期的 7 天内,因为这不包括某人在第 5 天完成任务但不是第 6 天......然后在第 7 天......同样它很复杂,因为每个用户都有不同的开始日期。所以我可能今天开始了任务,而另一个用户 5 天前开始了任务。我可以安全地假设所有超过 7 天的日期都已过期,但这并不能真正帮助确定天数。
我很困惑如何真正完成这项任务。
将您的数据保存在数据库中,因为 cookie 的问题是用户可以随时清理 his/her 浏览器。数据库中的数据可以随时处理。
假设您在数据库中以这种格式保存数据:
Description | task_id | created
Task perfor. | 2 | 2016-10-17
Task perfor. | 2 | 2016-10-17
Task perfor. | 2 | 2016-10-18
Task perfor. | 2 | 2016-10-18
您可以通过运行查询删除数据:
delete from table where created = date
一个查询就可以清理你的数据,一点都不乱。即使是巨大的数据库也是这样处理的。
有几种方法可以做到这一点。
如果你要使用 db 路线,你可以参考这个 SQL fiddle
我不知道它的数据库密集程度如何,但我认为如果您要走这条路,那将总结所需的工作。这条路线的优点是你不必删除或重置任何东西,所以你将拥有历史数据,例如你可以通过将上面的查询更改为 having count(distinct d) < 7
来获得用户做了多少 "tries" (它会return 用户尝试完成任务的行数)
另一种方法是您可以使用基于文件的数据,例如在服务器端为每个执行任务的用户使用 JSON 文件。使用这条路线,您需要自己维护数据,例如您有这个简单的 JSON 结构:
{
"day1": "2016-09-01",
"last_task": "2016-09-03",
"accumulated_task": "56"
}
我所说的自己维护数据的意思是,每次应用更改时都需要更新它,例如当前日期是 2016-09-05
并且 last_task
是 2016-09-03
,那么你需要重置它。这条路线的好处当然是没有db开销,但是很多"manual labor".
这将假设我们的测试页面 id = 9 ... 已查看,计入徽章(用户连续 7 天查看该页面)。这一事实已从操作评论中删除(7 天和一个徽章)。至于第 9 页,我们刚刚在此答案中进行了补充。
因此,如果用户连续 7 天查看该页面,我们希望该用户出现在输出中。注意,页码是 9.
架构和数据加载
create schema db40076704;
use db40076704;
create table pageViews
( id int auto_increment primary key,
userId int not null,
viewDT datetime not null,
pageId int not null
-- include decent index choices here
-- include Foreign Key constraints here
);
truncate pageViews;
insert pageViews (userId,viewDT,pageId) values
(101,'2016-09-05 21:00:00',9),
(101,'2016-09-06 11:00:00',9),
(101,'2016-09-06 15:55:00',9),
(101,'2016-09-06 15:57:00',9),
(101,'2016-09-07 21:00:00',9),
(101,'2016-09-08 21:00:00',999999),
(101,'2016-09-09 21:00:00',9),
(101,'2016-09-10 21:00:00',9),
(101,'2016-09-11 21:00:00',9),
(150,'2016-09-01 21:00:00',9),
(150,'2016-09-06 11:00:00',9),
(150,'2016-09-06 15:55:00',9),
(150,'2016-09-06 15:57:00',9),
(150,'2016-09-07 21:00:00',9),
(150,'2016-09-08 10:44:00',9),
(150,'2016-09-09 21:00:00',9),
(150,'2016-09-10 21:00:00',9),
(150,'2016-09-11 23:00:00',9),
(150,'2016-09-12 23:00:00',9),
(200,'2016-09-08 10:44:00',9),
(200,'2016-09-10 21:00:00',9),
(200,'2016-09-12 21:00:00',9),
(200,'2016-09-14 23:00:00',9),
(200,'2016-09-16 23:00:00',9),
(200,'2016-09-18 23:00:00',9),
(200,'2016-09-20 23:00:00',9);
显示调试详细信息的内部查询
select userId,
date(viewDT),
(@rn := if(@curUser = userId
AND (@prevDate=DATE(viewDT) OR @prevDate=DATE_SUB(DATE(viewDT),INTERVAL 1 DAY)), @rn,
if(@curUser := GREATEST(userId,-1), @rn+1, @rn+1)
)
) rn,
@prevDate:=DATE(viewDT) as dummy1
from pageViews
join (select @curUser:=-1,@prevDate:='',@rn:=0) params
where pageId=9
order by userId,viewDt;
+--------+--------------+------+------------+
| userId | date(viewDT) | rn | dummy1 |
+--------+--------------+------+------------+
| 101 | 2016-09-05 | 1 | 2016-09-05 |
| 101 | 2016-09-06 | 1 | 2016-09-06 |
| 101 | 2016-09-06 | 1 | 2016-09-06 |
| 101 | 2016-09-06 | 1 | 2016-09-06 |
| 101 | 2016-09-07 | 1 | 2016-09-07 |
| 101 | 2016-09-09 | 2 | 2016-09-09 |
| 101 | 2016-09-10 | 2 | 2016-09-10 |
| 101 | 2016-09-11 | 2 | 2016-09-11 |
| 150 | 2016-09-01 | 3 | 2016-09-01 |
| 150 | 2016-09-06 | 4 | 2016-09-06 |
| 150 | 2016-09-06 | 4 | 2016-09-06 |
| 150 | 2016-09-06 | 4 | 2016-09-06 |
| 150 | 2016-09-07 | 4 | 2016-09-07 |
| 150 | 2016-09-08 | 4 | 2016-09-08 |
| 150 | 2016-09-09 | 4 | 2016-09-09 |
| 150 | 2016-09-10 | 4 | 2016-09-10 |
| 150 | 2016-09-11 | 4 | 2016-09-11 |
| 150 | 2016-09-12 | 4 | 2016-09-12 |
| 200 | 2016-09-08 | 5 | 2016-09-08 |
| 200 | 2016-09-10 | 6 | 2016-09-10 |
| 200 | 2016-09-12 | 7 | 2016-09-12 |
| 200 | 2016-09-14 | 8 | 2016-09-14 |
| 200 | 2016-09-16 | 9 | 2016-09-16 |
| 200 | 2016-09-18 | 10 | 2016-09-18 |
| 200 | 2016-09-20 | 11 | 2016-09-20 |
+--------+--------------+------+------------+
25 rows in set (0.00 sec)
使用以上内容的最终答案
SELECT userId,rn,count(*) days_In_A_Row
from
( SELECT userId,
DATE(viewDT),
(@rn := if(@curUser = userId
AND (@prevDate=DATE(viewDT) OR @prevDate=DATE_SUB(DATE(viewDT),INTERVAL 1 DAY)), @rn,
if(@curUser := GREATEST(userId,-1), @rn+1, @rn+1)
)
) rn,
@prevDate:=DATE(viewDT) as dummy1
FROM pageViews
JOIN (SELECT @curUser:=-1,@prevDate:='',@rn:=0) params
WHERE pageId=9
ORDER BY userId,viewDt
) xDerived
GROUP BY userId,rn
HAVING days_In_A_Row>6;
+--------+------+---------------+
| userId | rn | days_In_A_Row |
+--------+------+---------------+
| 150 | 4 | 9 |
+--------+------+---------------+
所以用户 150 至少连续 7 天查看第 9 页(实际上是连续 9 天)。该用户在您的系统中获得徽章。
有关 mysql 变量(@ 变量)的一些信息。要安全地使用变量,必须注意不要假设 select 的任何输出列会先于另一列触发。这是标题为 User-Defined Variables:
的手册页中清楚说明的事实In the following statement, you might think that MySQL will evaluate @a first and then do an assignment second:
SELECT @a, @a:=@a+1, ...;
However, the order of evaluation for expressions involving user variables is undefined.
也就是说,我们知道使用 GREATEST()、LEAST() 和 COALESCE() 等函数的优先级会更高。
此外,GREATEST(N,-1) 代码中的废话将始终为 return N。但是我们需要强制在
之前计算该列的优先级@prevDate:=DATE(viewDT) as dummy1
行。另见 Baron Schwartz 的 必读 Advanced MySQL user variable techniques.