Mysql计算连续每个用户连续60天

时间:2014-06-12 22:28:49

标签: mysql

我想从这个mysql表中计算60天内每个用户的最长“条纹”。 Streak意味着用户在这一天有一个条目。

+-----+------------+---------------------+
| id  | user       | date                |
+-----+------------+---------------------+
|   3 | test1      | 2014-06-10 23:55:01 |
|   4 | test2      | 2014-06-10 02:01:06 |
|   5 | test1      | 2014-06-11 23:55:06 |
|   6 | test2      | 2014-06-11 23:55:07 |
|   7 | test1      | 2014-06-12 23:55:07 |
|   9 | test1      | 2014-06-13 23:55:07 |
|   10| test2      | 2014-06-13 23:55:07 |

输出应如下所示:

test1  4
test2  2 no entry on  2014-06-12

但我不知道如何正确地做到这一点。

1 个答案:

答案 0 :(得分:4)

执行此操作的一种方法是使用MySQL用户变量。对于大型集合而言,这不一定是最有效的方法,因为它实现了两个内联视图。

SELECT s.user
     , MAX(s.streak) AS longest_streak
  FROM ( SELECT IF(@prev_user = o.user AND o.date = @prev_date + INTERVAL 1 DAY
                  , @streak := @streak + 1
                  , @streak := 1
                ) AS streak
              , @prev_user := o.user AS user
              , @prev_date := o.date AS `date`
           FROM ( SELECT t.user
                       , DATE(t.date) AS `date`
                    FROM mytable t
                   CROSS
                    JOIN (SELECT @prev_user := NULL, @prev_date := NULL, @streak := 1) i
                   WHERE t.date >= DATE(NOW()) + INTERVAL -60 DAY
                   GROUP BY t.user, DATE(t.date)
                   ORDER BY t.user, DATE(t.date)
                ) o
       ) s
 GROUP BY s.user

内联视图别名为 i 只是初始化一些用户变量;我们并不关心它返回什么,除了我们需要它因为JOIN操作而返回正好一行;我们真正关心在语句执行的早期初始化用户变量的副作用。

别名为 o 的内嵌视图获取用户和日期列表;规范是针对每个日期"的条目,因此我们可以截断时间部分,只获得DATE,并使用GROUP BY子句将其转换为不同的集合。

内联视图别名为 s 处理每一行,并将当前行的值保存到@prev_用户变量中。在覆盖值之前,它会将当前行的值与上一行的值(已保存)进行比较。如果用户匹配,并且当前行上的日期恰好比上一个日期晚1天,我们将继续"条纹",因此我们将@streak变量的当前值增加1.否则,之前的连胜被打破了,我们开始了一个新的"条纹",将@streak重置为1.

最后,我们处理来自 s 的行,以便为每个用户提取最大条纹。

(此声明只有桌面检查,可能有一两个错字。)