2016-02-27 45 views
0

我有一个事件表的形式:MYSQL计数行,直到最后一个不同的行

| User |  Event   | Date | 
| User A | Failed Log In  | ... | 
| User A | Failed Log In  | ... | 
| User B | Failed Log In  |   | 
| User A | Successful Log In |   | 
| User B | Successful Log In |   | 

我想要做的是计算每个用户所有的“失败日志插件”,因为最后'成功登录',所以我可以创建一个视图的形式:

| User | Failed Log in attempts | 
| User A |   2   | 
| User B |   1   | 

这是可能在SQL中做?或者我需要将这个逻辑拉入我的应用程序?

+2

我们必须假设你的表有一个ID或日期/时间栏指定排序。 –

+0

@GordonLinoff是的,谢谢你指出 – Edd

回答

2

SQL表格代表无序集合,因此除非列指定排序,否则不存在“last”或“before”。所以,这个答案假设某种eventdatetime列与该信息,但自动递增id将工作得很好(可能更好)。

我想这你想要做什么:

select e.user, count(*) as NumFailedAttempts 
from events e 
where e.event = 'Failed Log In' and 
     e.eventdatetime > (select max(e2.eventdatetime) 
         from events e2 
         where e2.user = e.user and e2.event = 'Successful Log In' 
         ); 

如果你想包括零(那些没有登录失败),那么你就可以离开这个加入到用户表。

+0

@quasoft。 。 。这对于文本来说是有意义的(我改变了答案)。我正在看桌子,并假设新排在底部,而不是顶部。 –

1

到@GordonLinoff答案的替代(这是正确的),可能是加入了表本身,为了得到最后的登录时间,而不是使用子查询:

SELECT events.user, COUNT(events.event) AS FailedCount 
FROM events 
LEFT JOIN (
    SELECT MAX(`date`) AS lastlogin 
    FROM events 
    WHERE event = 'Success' 
) AS last ON (events.user = last.user) 
WHERE 
    event = 'Failed' 
    AND 
    `date` > last.lastlogin 
GROUP BY user, event 

http://sqlfiddle.com/#!9/96faa/1/0

这样做是:

  • 加入events表本身,从而增加临时lastLogin场的每一行;
  • 选择上次登录后发生的失败事件;
  • 将已过滤的失败事件列表组合起来进行计数。

加入表格本身的简短介绍可在MySQL documentation: Using More Than one Table和本文中获得:Joining a Table to Itself

这可能会给子查询变量带来最小的性能优势。实际上它是主观的,取决于DBMS的特定版本和查询优化器的“心情”。

约联接VS子查询的性能的讨论可以在这里找到:

相关问题