2013-01-21 71 views
3

基本上相關記錄的記錄,我試圖結局是:「獲得成功記錄有一定的時間到過去在0 不成功記錄數」。 「成功」和「不成功」只是指一列的價值。查找在過去

雖然這是一個有點複雜,這裏的表我處理的描述:

`log` 
    id    int PRIMARY KEY AUTO_INCREMENT 
    fingerprint_id int (foreign key) 
    status   boolean 
    date    timestamp 

我們的小系統的工作流程是,當用戶掃描他們的指紋,記錄是添加到此表並status基於它是否匹配(再次,還有更多,我只是想簡化)。我們得到fingerprint_id的基礎是用戶這樣做,所以這是相關記錄給一個人的標識符。

現在,我們要求他們最多嘗試3次。所以,他們可以在3日的第一場比賽中,3場比賽中的第2場比賽,或3場比賽中的第3場比賽,或者根本沒有比賽。這意味着他們可以在他們的「組」中有1,2或3條記錄。雖然這不是事實,但我們可以假設用戶會繼續嘗試,直到他們匹配或達到3次失敗的嘗試(我們發現有時人們在失敗一次或兩次後可能不會繼續)。

這裏的一些數據的一個例子:

id fp_id status date 
---------------------------------------- 
20 2  0  '2013-01-21 12:30:01' 
21 2  0  '2013-01-21 12:30:05' 
22 2  0  '2013-01-21 12:30:10' 
23 9  1  '2013-01-21 12:31:30' 
24 1  0  '2013-01-21 12:35:00' 
25 1  1  '2013-01-21 12:35:05' 

在數據,用戶(fingerprint_id)2嘗試3次,並從不匹配。用戶9在他們的第一次嘗試中匹配。用戶1嘗試過一次失敗,然後再次嘗試匹配。

問題的關鍵是要在35秒內找出有多少次成功(status = 1)日誌記錄有0次失敗(status = 0)記錄。當然,「連接」它們的唯一方法是fingerprint_id

再一次,我們假設很多東西,但沒關係。

這裏是我的嘗試:

SELECT COUNT(*) 
FROM log AS log_main 
WHERE log_main.status=1 AND 
     (SELECT COUNT(*) 
     FROM log AS log_inner 
     WHERE log_inner.fingerprint_id=log_main.fingerprint_id AND 
       log_inner.status=0 AND 
       log_inner.date<log_main.date AND log_inner.date>=(log_main.date - INTERVAL 35 SECOND))=0 

^我希望這一次選擇的是有在35秒前發生(該用戶)的0失敗記錄的計數所有成功的記錄。但我不知道,因爲查詢需要600秒以上。我剛剛發現如何擴展MySQL Workbench的最大超時時間,但無論如何,這需要很長時間。該表總共有大約120,000條記錄,所以我不確定是否足以使這個查詢變得緩慢。

不管怎麼說,這裏的另一個嘗試:

SELECT COUNT(*) 
FROM (SELECT log.fingerprint_id, log.date 
     FROM log 
     WHERE log.status=1) successful, 
     (SELECT log.fingerprint_id, log.date 
     FROM log 
     WHERE log.status=0) unsuccessful 
WHERE successful.fingerprint_id=unsuccessful.fingerprint_id AND 
     unsuccessful.date<successful.date AND unsuccessful.date>=(successful.date - INTERVAL 35 SECOND) 

^我覺得像這樣的接近,但當然,還有一個如何對多條記錄,在過去匹配的「數」沒有可比性。這是我對如何解決困惑的部分。我有一種感覺,它與GROUP BY有關,或者使用IN,但是我所做的似乎並不奏效(從600多秒的意義上說,它就是這樣)。下面是我用GROUP BY

SELECT successful.id, COUNT(*) cnt 
FROM (SELECT log.fingerprint_id, log.date, log.id 
     FROM log 
     WHERE log.status=1) successful, 
     (SELECT log.fingerprint_id, log.date, log.id 
     FROM log 
     WHERE log.status=0) unsuccessful 
WHERE successful.fingerprint_id=unsuccessful.fingerprint_id AND 
     unsuccessful.date<successful.date AND unsuccessful.date>=(successful.date - INTERVAL 35 SECOND) 
GROUP BY successful.id 

試過^但結果只包含那些沒有0計數行的一些例子。我猜這是因爲WHERE條款。但我只需要0計數。

我試過這麼多的組合,我想我的大腦只是被炸。

+0

一點:關於運行這麼長時間的查詢,你有索引,你需要這些查詢有機會執行好嗎? – DWright

+0

@DWright我有一種感覺可能是一個問題。不幸的是,我們沒有。巧合的是,我是在不久前加入團隊的時候決定開始清理數據庫的人,並且已經有查詢準備添加INDEX。問題是我正在生產服務器上測試這些查詢(數據真的很重要),並且寧願等到今晚有些停機時間才能修改表。對我來說,INDEXes在'fingerprint_id'和'date'列上有意義。這可能是對的嗎? – Ian

回答

1

嘗試使用NOT EXISTS而不是COUNT = 0。這應該表現得更好。

SELECT COUNT(*) 
FROM log AS log_main 
WHERE log_main.status=1 
AND  NOT EXISTS 
     ( SELECT 1 
      FROM log AS log_inner 
      WHERE log_inner.fingerprint_id=log_main.fingerprint_id 
      AND  log_inner.status = 0 
      AND  log_inner.date < log_main.date 
      AND  log_inner.date >= (log_main.date - INTERVAL 35 SECOND) 
     ); 

您還應該確保表格已正確編制索引。

編輯

我相信使用LEFT JOIN/IS NULL是在MySQL比使用NOT EXISTS更有效,因此這將執行比上述更好(儘管也許不顯著):

SELECT COUNT(*) 
FROM log AS log_main 
     LEFT JOIN log AS log_inner 
      ON log_inner.fingerprint_id=log_main.fingerprint_id 
      AND log_inner.status = 0 
      AND log_inner.date < log_main.date 
      AND log_inner.date >= (log_main.date - INTERVAL 35 SECOND) 
WHERE log_main.status = 1 
AND  Log_inner.fingerprint_id IS NULL; 

EDIT 2

要獲得記錄1或2次嘗試等,我仍然會使用JOIN,但如此:

SELECT COUNT(*) 
FROM ( SELECT log_Main.id 
      FROM log AS log_main 
        INNER JOIN log AS log_inner 
         ON log_inner.fingerprint_id=log_main.fingerprint_id 
         AND log_inner.status = 0 
         AND log_inner.date < log_main.date 
         AND log_inner.date >= (log_main.date - INTERVAL 35 SECOND) 
      WHERE log_main.status = 1 
      AND  Log_inner.fingerprint_id IS NULL 
      GROUP BY log_Main.id 
      HAVING COUNT(log_Inner.id) = 1 
     ) d 
+0

誰知道我過去是否曾嘗試過。我會很樂意給你一個鏡頭,讓你知道。感謝您的建議! – Ian

+0

是的,大腦肯定炸了。這些都是有道理的,所以我希望他們能夠工作(更好)! – Ian

+0

所以花了2000多秒,但它似乎工作。我可能不得不調整它,因爲有一些奇怪的場景...反正,這似乎是正確的!我討厭問,但你能幫我多做一件事嗎?我知道在我的問題中,我問過如何獲得記錄有0條相關記錄......並且您給了我答案......但是有沒有辦法做類似於您的解決方案的事情來匹配具有1條記錄的記錄2,相關記錄?而不是0?我知道它比0更容易,因爲您可以檢查是否存在,但我也在查找特定數量的記錄。具體來說,1,也是2 – Ian

相關問題