mysql – 检查连续x天 – 给定数据库中的时间戳

任何人都可以给我一个想法或暗示如何在数据库表(MySQL)中连续检查X,其中存储登录(用户ID,时间戳)?

Stackoverflow做它(例如像爱好者的徽章 – 如果你连续30天连续登录…).你将要使用什么功能,或者怎么做呢?

像SELECT 1 FROM login_dates WHERE …?

最佳答案
您可以使用移位的自外连接与变量结合来实现此目的.看到这个解决方案:

SELECT IF(COUNT(1) > 0, 1, 0) AS has_consec
FROM
(
    SELECT *
    FROM
    (
        SELECT IF(b.login_date IS NULL, @val:=@val+1, @val) AS consec_set
        FROM tbl a
        CROSS JOIN (SELECT @val:=0) var_init
        LEFT JOIN tbl b ON 
            a.user_id = b.user_id AND
            a.login_date = b.login_date + INTERVAL 1 DAY
        WHERE a.user_id = 1
    ) a
    GROUP BY a.consec_set
    HAVING COUNT(1) >= 30
) a

如果用户在过去的任何一个月连续30天或更长时间内登录,这将返回1或0.

这个查询首当其冲的是第一个subselect.让我们仔细看一下,以便我们能够更好的理解这是如何工作的:

使用以下示例数据集:

CREATE TABLE tbl (
  user_id INT,
  login_date DATE
);

INSERT INTO tbl VALUES
(1, '2012-04-01'),  (2, '2012-04-02'),
(1, '2012-04-25'),  (2, '2012-04-03'),
(1, '2012-05-03'),  (2, '2012-04-04'),
(1, '2012-05-04'),  (2, '2012-05-04'),
(1, '2012-05-05'),  (2, '2012-05-06'),
(1, '2012-05-06'),  (2, '2012-05-08'),
(1, '2012-05-07'),  (2, '2012-05-09'),
(1, '2012-05-09'),  (2, '2012-05-11'),
(1, '2012-05-10'),  (2, '2012-05-17'),
(1, '2012-05-11'),  (2, '2012-05-18'),
(1, '2012-05-12'),  (2, '2012-05-19'),
(1, '2012-05-16'),  (2, '2012-05-20'),
(1, '2012-05-19'),  (2, '2012-05-21'),
(1, '2012-05-20'),  (2, '2012-05-22'),
(1, '2012-05-21'),  (2, '2012-05-25'),
(1, '2012-05-22'),  (2, '2012-05-26'),
(1, '2012-05-25'),  (2, '2012-05-27'),
                    (2, '2012-05-28'),
                    (2, '2012-05-29'),
                    (2, '2012-05-30'),
                    (2, '2012-05-31'),
                    (2, '2012-06-01'),
                    (2, '2012-06-02');

这个查询:

SELECT a.*, b.*, IF(b.login_date IS NULL, @val:=@val+1, @val) AS consec_set
FROM tbl a
CROSS JOIN (SELECT @val:=0) var_init
LEFT JOIN tbl b ON 
    a.user_id = b.user_id AND
    a.login_date = b.login_date + INTERVAL 1 DAY
WHERE a.user_id = 1

会产生:

正如你所看到的,我们正在做的是将连接的表转移1天.对于前一天不连续的每一天,LEFT JOIN生成NULL值.

现在我们知道不连续的日子在哪里,我们可以使用变量来区分每一组连续的天数,方法是检测移位表的行是否为NULL.如果它们为NULL,那么日期不是连续的,所以只需增加变量.如果它们不为NULL,那么不要增加变量:

在使用增量变量对每个连续天数进行区分之后,只需简单地对每个“set”(在consec_set列中定义)进行分组,并使用HAVING过滤掉任何小于指定值的集合连续几天(30例)

最后,我们把THAT查询换成一个连续30天以上的套数.如果有一个或多个这些集合,则返回1,否则返回0.

SQLFiddle step-by-step demo

转载注明原文:mysql – 检查连续x天 – 给定数据库中的时间戳 - 代码日志