2016-02-27 42 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子查詢的性能的討論可以在這裏找到:

相關問題