在MySQL的最后'n'天中连续事件的另一个计数/排名

时间:2015-09-02 14:50:28

标签: mysql

我无法设置查询来计算/排列上一次' n '天内事件发生的连续天数。即:如果事件在最后' n '天内连续发生' k '次,则与参考日期无间隙。

从当前日期到过去' n '天的视觉(0表示无事件,1表示事件):

case A - 01111 (count as 0 since there's no event in the previous date).
case B - 11001 (count as 2 consecutive days)
case C - 11110 (count as 4 consecutive days)
case D - 00110 (also count as 0)
case E - 10111 (count as 1)... and so on

考虑'伪'结构:

Table1
uid
eventid

table2
eventid
datetime

我需要的结果是uid的'等级'在最近n天内有连续事件,所以如果我在表1和表2中得到这些值:

Table1
(1, 100)
(1, 101)
(1, 102)
(1, 103)
(2, 104)
(2, 105)
(2, 106)

Table2
(100, '2015-09-11 00:00:00')
(101, '2015-09-10 00:00:00')
(102, '2015-09-09 00:00:00')
(103, '2015-09-07 00:00:00')
(104, '2015-09-11 00:00:00')
(105, '2015-09-10 00:00:00')
(106, '2015-09-05 00:00:00')

结果应该是:

uid - consecutive
1 - 3
2 - 2

这意味着uid 1在最后几天连续发生了事件100,101和102但是偶数103因为不连续而被淘汰。

我正在寻找similar questions并尝试应用其中一些,但没有人根据参考(当前)日期考虑连续几天。

接近我来的是使用每个案例的日期进行左连接,类似于:

SELECT * FROM
(SELECT * FROM Table1 LEFT JOIN Table2 USING (uid) WHERE date(datetime)=curdate()-interval 3 day) 
LEFT JOIN (SELECT * FROM Table1 LEFT JOIN Table2 USING (uid) WHERE date(datetime)=curdate()-interval 2 day)
LEFT JOIN (SELECT * FROM Table1 LEFT JOIN Table2 USING (uid) WHERE date(datetime)=curdate()-interval 1 day)

此外,我在SQL中使用var的知识几乎都没有,如果可能的话,我想避免使用过程,从php内部调用mysql。

THX

1 个答案:

答案 0 :(得分:1)

您可以使用计数器变量来做到这一点。

首先,我们会获得一个包含uiddatetime列的表格,并且排序正确:

SELECT `uid`,`datetime` FROM `table1`
INNER JOIN `table2` ON `table1`.`eventid`=`table2`.`eventid`
ORDER BY `uid`, `datetime`

现在我们将其用作子查询,每当uid与最后一行相同时推进计数器,datetime比最后一行的日期提前1天。以下是它的完成方式:

SET @counter = 1;
SET @lastDate = '2010-01-01 00:00:00';
set @lastUid = 0;

SELECT
  `uid`,
  IF (((DATE_ADD(@lastDate, INTERVAL 1 DAY)=`datetime`) AND (`uid`=@lastUid)),
    @counter := @counter+1, @counter := 1),
  (@lastUid := `uid`),
  (@lastDate := `datetime`),
  @counter as `counter`
FROM (
  SELECT `uid`,`datetime` FROM `table1`
  INNER JOIN `table2` ON `table1`.`eventid`=`table2`.`eventid`
  ORDER BY `uid`, `datetime` ASC
  ) `uidDateTable`

现在我们要做的就是将该查询用作子查询,并找到每MAX counter uid的{​​{1}}值。这就是你需要的实际查询:

SET @counter = 1;
SET @lastDate = '2010-01-01 00:00:00';
set @lastUid = 0;

SELECT `uid`, max(`counter`)
FROM (
  SELECT
    `uid`,
    IF (((DATE_ADD(@lastDate, INTERVAL 1 DAY)=`datetime`) AND (`uid`=@lastUid)),
      @counter := @counter+1, @counter := 1),
    (@lastUid := `uid`),
    (@lastDate := `datetime`),
    @counter as `counter`
  FROM (
    SELECT `uid`,`datetime` FROM `table1`
    INNER JOIN `table2` ON `table1`.`eventid`=`table2`.`eventid`
    ORDER BY `uid`, `datetime` ASC
    ) `uidDateTable`
  ) `uidCounters`
GROUP BY `uid`;