2013-06-27 133 views
0

我的Widget銷售人員有一個呼叫記錄。記錄客戶記錄中的每次點擊。工作人員每天可以訪問同一個客戶帳戶幾次,因此在一天的不同時間可能會有數十個連續點擊在同一個記錄ID下分組在一起。獲取連續記錄視圖的持續時間

實施例:

recordID userID date_event 
33450 321  2013-06-20 16:22:02 
33450 321  2013-06-20 16:22:02 
33450 321  2013-06-20 16:22:24 
33450 321  2013-06-20 16:22:24 
22222 321  2013-06-20 16:22:53 
22222 321  2013-06-20 16:22:54 
12345 321  2013-06-20 16:23:43 
12345 321  2013-06-20 16:23:44 
12345 321  2013-06-20 16:24:00 
12345 321  2013-06-20 16:24:05 
12345 321  2013-06-20 16:24:05 
12345 321  2013-06-20 18:16:09 
12345 321  2013-06-20 18:16:09 
33450 321  2013-06-20 18:33:24 
33450 321  2013-06-20 18:35:11 
33450 321  2013-06-20 18:36:55 
12345 321  2013-06-20 19:01:14 
98765 321  2013-06-20 19:02:43 

在上述數據集,我會6組的訪問權限。

 first    last     duration(seconds) 
33450 2013-06-20 16:22:02 2013-06-20 16:22:24  22 
22222 2013-06-20 16:22:30 2013-06-20 16:22:54  24 
12345 2013-06-20 16:23:43 2013-06-20 18:16:09  6746 
33450 2013-06-20 18:33:24 2013-06-20 18:36:55  211 
12345 2013-06-20 19:01:14 2013-06-20 19:01:14  0 
98765 2013-06-20 19:02:43 2013-06-20 19:02:43  0 

持續時間是一個估計,而不是眼睛在記錄上的實際時間。我無法檢測到工作人員何時主動使用此應用程序,或者當他們使用客戶端工具時,在另一個應用程序或網站中查找數據。

表結構是:

CREATE TABLE IF NOT EXISTS `record_log` (
    `event_id` int(11) NOT NULL AUTO_INCREMENT, 
    `userID` int(5) DEFAULT NULL, 
    `recordID` int(10) DEFAULT NULL, 
    `date_event` datetime DEFAULT NULL, 
    PRIMARY KEY (`event_id`), 
    KEY `userID` (`userID`), 
    KEY `date_event` (`date_event`), 
    KEY `recordID` (`recordID`), 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; 

什麼是構建一個查詢,以返回第二個數據集的最佳方法?這可以在一個查詢中完成,而不需要使用太多的週期?我可能會在某一天有數千條訪問記錄。

+0

你有一個auto_increment ID?你的記錄如何分組? recordID發生變化時組會發生變化? – fthiella

+0

是的 - auto_increment是「event_id」。記錄將按recordID分組,但捕獲的是,對於給定的時間段,我需要的不僅僅是每個記錄ID的所有持續時間的簡單總和。同一個recordID可以在一天中多次訪問。通常會有一組連續的活動。或者,記錄ID可能只在一天中的某個時間被訪問。我試着在上面的數據中解釋和顯示這一點。 –

回答

1

是的,可以返回指定的結果集,但不是很好。特別是,使用內聯視圖(MySQL稱之爲「派生表」)意味着行將被寫入臨時MyISAM表,並且該操作對於大集合可能是昂貴的,因此使用此方法獲得性能將會可能需要一些關於最內層查詢的謂詞來獲得合理大小的一組數據......例如,

WHERE q.userID = 321 
     AND q.date_event >= '2012-01-01' 
     AND q.date_event < '2012-01-02' 

注意:它看起來像的「持續時間」的值應限制......也就是說你會在下午6時想上週五點擊上午8點到「匹配」的點擊週一,應該說是視爲「持續時間」的一部分。在下面的查詢中,我將最大持續時間值指定爲6800秒,這樣6800是可以返回的最大持續時間,任何比這更大的持續時間都會「分裂」爲兩個持續時間。

下面是返回指定的結果集的查詢的例子:

SELECT recordID 
    -- , s.userID 
    , s.first 
    , MAX(s.date_event) AS `last` 
    , MAX(TIMESTAMPDIFF(SECOND,s.first,s.date_event)) AS duration 
    -- , MAX(s.cnt) AS `cnt` 
    FROM ( 
     SELECT IF(r.recordID = @record_id AND r.userID = @user_id AND r.date_event < (@date_event + INTERVAL 6800 SECOND), 
       @cnt := @cnt + 1, @cnt := 1) AS `cnt` 
       , IF(r.recordID = @record_id AND r.userID = @user_id AND r.date_event < (@date_event + INTERVAL 6800 SECOND), 
       @first, @first := r.date_event) + INTERVAL 0 SECOND AS `first` 
       , @record_id := r.recordID AS recordID 
       , @user_id := r.userID AS userID 
       , @date_event := r.date_event AS date_event 
      FROM (SELECT @record_id := NULL, @user_id := NULL, @date_event := NULL, @cnt := 0, @first := NULL) i 
      JOIN (SELECT q.recordID, q.userID, q.date_event 
        FROM record_log q 
        ORDER BY q.userID, q.date_event, q.recordID 
       ) r 
     ) s 
GROUP 
    BY s.first 
    , s.userID 
    , s.recordID 
ORDER 
    BY s.first 
    , s.userID 
    , s.recordID 

注:此查詢假設在一個記錄中的「時間」,將「打破了」由另一記錄中的「持續時間」。 (如果用戶點擊的記錄,然後點擊不同的記錄,然後回來一些更多的點擊原始記錄,在原始記錄的點擊將被計數爲兩個獨立的持續時間。


樣本數據:

INSERT INTO record_log (recordID, userID, date_event) VALUES 
('33450','321','2013-06-20 16:22:02') 
,('33450','321','2013-06-20 16:22:02') 
,('33450','321','2013-06-20 16:22:24') 
,('33450','321','2013-06-20 16:22:24') 
,('22222','321','2013-06-20 16:22:53') 
,('22222','321','2013-06-20 16:22:54') 
,('12345','321','2013-06-20 16:23:43') 
,('12345','321','2013-06-20 16:23:44') 
,('12345','321','2013-06-20 16:24:00') 
,('12345','321','2013-06-20 16:24:05') 
,('12345','321','2013-06-20 16:24:05') 
,('12345','321','2013-06-20 18:16:09') 
,('12345','321','2013-06-20 18:16:09') 
,('33450','321','2013-06-20 18:33:24') 
,('33450','321','2013-06-20 18:35:11') 
,('33450','321','2013-06-20 18:36:55') 
,('12345','321','2013-06-20 19:01:14') 
,('98765','321','2013-06-20 19:02:43') 
+0

快速跟進。爲什麼要使用'q.date_event> ='2012-01-01'和q.date_event <'2012-01-02''而不是'DATE(q.date_event)='2012-01-01''? –

+1

好問題。在一個謂詞(WHERE子句)中,我們不希望將一個列包裝在一個函數中,因爲這樣做會禁用列上的索引以滿足查詢。在裸露列的範圍內,可以使用索引。但是,如果我們使用'DATE(q.date_event)',那麼這將有效地強制MySQL爲表中的每行計算表達式(即調用DATE函數)。 (實際上,這是最糟糕的情況;如果行先被另一個謂詞過濾掉,那麼MySQL可以跳過對已經過濾的行的表達式進行評估。) – spencer7593

0

我會用一個SQL查詢與變量:

SELECT 
    recordID, 
    userID, 
    MIN(date_event) first, 
    MAX(date_event) last, 
    TIME_TO_SEC(TIMEDIFF(MAX(date_event), MIN(date_event))) sec 
FROM (
    SELECT 
    events.*, 
    CASE WHEN @last_recordID=recordID THEN @grp ELSE @grp:[email protected]+1 END groupID, 
    @last_recordID := recordID 
    FROM 
    events, (SELECT @grp:=0, @last_recordID:=NULL) r 
    ORDER BY 
    event_ID 
) s 
GROUP BY 
    recordID, 
    userID, 
    groupID 
ORDER BY 
    groupID 

請參閱小提琴here

0

最簡單的查詢返回的數據集將是:

SELECT recordID, MIN(date_event) AS `first`, MAX(date_event) AS `last` 
, TIMESTAMPDIFF(SECOND, MIN(date_event), MAX(date_event)) AS `duration(seconds)` 
FROM `record_log` 
GROUP BY recordID 

另一種選擇,可能會更快是剛剛弄清楚持續時間的合理估計每一個客戶記錄被訪問的​​時間。以下查詢每次訪問使用30秒:

SELECT recordID, COUNT(*) AS staff_clicks, 30*COUNT(*) AS `estimated duration(seconds)` 
FROM `record_log` 
GROUP BY recordID 

這些都是非常基本的,但他們確實回答了您的原始問題。有很多的選擇,但很難知道要什麼規定沒有更多的信息(時間限制,所需的準確度等)

+0

這確實是更簡單的查詢。不幸的是,它不返回指定的結果集。例如,對於recordID 33450,它將返回一行,持續時間爲「2013-06-20 16:22:02」 - 「2013-06-20 18:36:55」,而不是如圖所示的兩個單獨的持續時間在說明書中。 – spencer7593