计算具有特定状态的连续行

时间:2014-08-29 07:16:34

标签: mysql count rows

我需要计算用户在过去一小时内是否连续三次失败登录尝试。

例如

id    userid    status  logindate
1     1         0       2014-08-28 10:00:00
2     1         1       2014-08-28 10:10:35
3     1         0       2014-08-28 10:30:00 
4     1         0       2014-08-28 10:40:00

在上面的示例中,状态0表示尝试失败,1表示成功尝试。

我需要一个查询,它将计算在过去一小时内发生状态为0的用户的三个连续记录。

我在下面尝试了查询

SELECT COUNT( * ) AS total, Temp.status
FROM (
SELECT a.status, MAX( a.id ) AS idlimit
FROM loginAttempts a
GROUP BY a.status
ORDER BY MAX( a.id ) DESC
) AS Temp
JOIN loginAttempts t ON Temp.idlimit < t.id
HAVING total >1

结果:

total       status
2             1

我不知道为什么它显示为 1 的状态。我还需要在logindate和status字段中添加where条件,但不知道它是如何工作的

2 个答案:

答案 0 :(得分:2)

对于连续计数,您可以使用用户定义的变量来记录系列值,如下面的查询我使用@g@r变量,在内部查询中我存储的当前状态值可以是1/0,如果表达式我将@g中存储的值与状态列进行比较,如果它们都相等,则@g保持前一行值,前一行的状态等于当前行的状态然后不要更改存储在@r中的值,如果这些值与@g <> a.status不匹配,那么将@r增加为1,有一点需要注意我正在使用带有id列的顺序并假设它设置为auto_increment,因此对于连续的1 @r值将与@r相同,第一个状态1为3,再次状态为1,因此@r将为3,直到状态发生变化状态0反之亦然0反之亦然


SELECT t.userid,t.consecutive,t.status,COUNT(1) consecutive_count
FROM (
SELECT a.* ,
@r:= CASE WHEN @g = a.status THEN @r ELSE @r + 1 END consecutive,
@g:= a.status g
FROM attempts a
CROSS JOIN (SELECT @g:=2, @r:=0) t1
WHERE a.`logindate` BETWEEN '2014-08-28 10:00:00' AND '2014-08-28 11:00:00'
ORDER BY id
) t
GROUP BY t.userid,t.consecutive,t.status
HAVING consecutive_count >= 3 AND  t.status = 0

现在在父查询中,我按userid对结果进行分组,案例表达式的结果值我有名称是consecutivestatus来获取每个用户的连续状态的计数< / p>


  

有一点要注意上面的查询,它必须提供   像我之间使用的小时范围没有这个将会更多   很难在一小时内准确找到3个连续状态

样本数据

INSERT INTO attempts
    (`id`, `userid`, `status`, `logindate`)
VALUES
    (1, 1, 0, '2014-08-28 10:00:00'),
    (2, 1, 1, '2014-08-28 10:10:35'),
    (3, 1, 0, '2014-08-28 10:30:00'),
    (4, 1, 0, '2014-08-28 10:40:00'),
    (5, 1, 0, '2014-08-28 10:50:00'),
    (6, 2, 0, '2014-08-28 10:00:00'),
    (7, 2, 0, '2014-08-28 10:10:35'),
    (8, 2, 0, '2014-08-28 10:30:00'),
    (9, 2, 1, '2014-08-28 10:40:00'),
    (10, 2, 1, '2014-08-28 10:50:00')
;

从id 3到5你可以看到你可以看到用户ID 1的连续0,同样id 6到8用户ID 2连续0并且他们在一个小时范围内使用上面的查询你可以得到如下结果

userid  consecutive  status  consecutive_count  
------  -----------  ------  -------------------
     1            2       0                    3
     2            2       0                    3

Fiddle Demo

答案 1 :(得分:0)

M Khalid Junaid的答案很棒,但当我点击它时,他的小提琴演示并不适合我。

这是Fiddle Demo,在撰写本文时起作用。

如果以后它没有工作,我在架构中使用了以下内容:

CREATE TABLE attempts
    (`id` int, `userid` int, `status` int, `logindate` datetime);

INSERT INTO attempts
    (`id`, `userid`, `status`, `logindate`)
VALUES
    (1, 1, 0, '2014-08-28 10:00:00'),
    (2, 1, 1, '2014-08-28 10:10:35'),
    (3, 1, 0, '2014-08-28 10:30:00'),
    (4, 1, 0, '2014-08-28 10:40:00'),
    (5, 1, 0, '2014-08-28 10:50:00'),
    (6, 2, 0, '2014-08-28 10:00:00'),
    (7, 2, 0, '2014-08-28 10:10:35'),
    (8, 2, 0, '2014-08-28 10:30:00'),
    (9, 2, 1, '2014-08-28 10:40:00'),
    (10, 2, 1, '2014-08-28 10:50:00')
;

这是查询:

SELECT t.userid,t.consecutive,t.status,COUNT(1) consecutive_count
FROM (
  SELECT a.* ,
    @r:= CASE WHEN @g = a.status THEN @r ELSE @r + 1 END consecutive,
    @g:= a.status g
  FROM attempts a
  CROSS JOIN (SELECT @g:=2, @r:=0) t1
  WHERE a.`logindate` BETWEEN '2014-08-28 10:00:00' AND '2014-08-28 11:00:00'
  ORDER BY id
) t
GROUP BY t.userid,t.consecutive,t.status
HAVING consecutive_count >= 3 AND  t.status = 0;