我想从这个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
但我不知道如何正确地做到这一点。
答案 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 的行,以便为每个用户提取最大条纹。
(此声明只有桌面检查,可能有一两个错字。)