2013-09-28 44 views
0

我正在建立一個MySQL查詢,但我卡住了...(我每分鐘記錄) 我有3個表。日誌,log_field,log_value。Mysql查詢跳過行並檢查狀態變化

logs -> id, create_time 
log_value -> id, log_id,log_field_id,value 
log_field -> id, name (one on the entries is status and username) 

的狀態的值可以是在線,離線和閒置...

我想看到的是從我的查詢是: 當我的日誌有人從狀態的變化,我想與create_time,用戶名,狀態行。

因此,對於給定的用戶,我希望我的查詢跳過行直到出現新的狀態... 而且我需要能夠放置忽略狀態更改的時間間隔。

有人可以幫忙嗎?

+0

你可以發佈一些示例數據,並顯示你希望從中得到什麼......我很確定我理解,但示例數據會有所幫助。不要使用製表符將列和空格對齊。並且一旦所有數據排列整齊,突出顯示整個分段並單擊花括號的按鈕,以便S/O將其視爲格式化的代碼,將單詞作爲原始問題的一部分包裝文本。 – DRapp

回答

0

儘管您沒有任何區別您帖子中列出的實際「用戶」(例如用戶ID)的內容,以及如果您有兩個「John Smith」名稱會發生​​什麼情況。

首先,介紹MySQL @variables。您可以將它們視爲在查詢處理行時運行的內聯程序。您可以創建變量,然後在每行處理完畢後將其更改,按照相同的順序進行更改,因爲字段選擇中的:=賦值是重要的。我會很快回覆。

第一個前提。您有一個可以/可以記錄的所有可能字段的字段值表。其中有兩個存在......一個是用戶名,另一個是您正在查看日誌的狀態已更改。我不知道這些內部「ID」號碼是什麼,但它們必須是每個現有表格的固定值。在我的場景中,我假設字段ID = 1是用戶的名稱,字段ID 2 =狀態列...否則,您需要兩個更多的連接才能獲取字段表,以確認哪個字段是您的字段通緝。很明顯,我的「ID」字段值與您的生產表不匹配,所以請相應地更改這些值。

這裏的查詢......

select FinalAlias.* 
from (
select 
     PQ.*, 
     if(@lastUser = PQ.LogUser, 1, 0) as SameUser, 
     @lastTime := if(@lastUser = PQ.LogUser, @lastTime, @ignoreTime) as lastChange, 
     if(PQ.create_time > @lastTime + interval 20 minute, 1, 0) as BeyondInterval, 
     @lastTime := PQ.create_time as chgTime, 
     @lastUser := PQ.LogUser as chgUser 
    from 
     (select 
       ByStatus.id, 
       l.create_time, 
       ByStatus.Value LogStatus, 
       ByUser.Value LogUser 
      from 
       log_value as ByStatus 
       join logs l 
        on ByStatus.log_id = l.id 
       join log_value as ByUser 
        on ByStatus.log_id = ByUser.log_id 
        AND ByUser.log_field_id = 1 
      where 
       ByStatus.log_field_id = 2 
      order by 
       ByUser.Value, 
       l.create_time) PQ, 
     (select @lastUser := '', 
       @lastTime := now(), 
       @ignoreTime := now()) sqlvars 
     ) FinalAlias 
    where 
      SameUser = 1 
     and BeyondInterval = 1 

現在,這是怎麼回事。最內層查詢(結果別名PQ代表「PreQuery」)只是要求field_id = 2(狀態列)存在的所有日誌值。從該日誌條目中,轉到日誌表的創建時間...在我們處於該狀態時,將AGAIN加入到同一個日誌ID的日誌值表中,但是這次也查找field_id = 1,以便我們可以獲取用戶名。

完成後,獲取所有按用戶預先排序的日誌ID,創建時間,狀態值和用戶名,並按時間順序排列。這是關鍵的一步。數據必須按用戶/時間預先組織,以將給定用戶的「最後」時間與他們的日誌狀態更改的「下一次」時間進行比較。

現在,MySQL @variables。將prequery加入另一個給出「sqlvars」查詢別名的@variables選擇。這將預先初始化變量fo @lastUser,@lastTime和@ignoreTime。現在,看看我在場上列表,經由部分

 if(@lastUser = PQ.LogUser, 1, 0) as SameUser, 
     @lastTime := if(@lastUser = PQ.LogUser, @lastTime, @ignoreTime) as lastChange, 
     if(PQ.create_time > @lastTime + interval 20 minute, 1, 0) as BeyondInterval, 
     @lastTime := PQ.create_time as chgTime, 
     @lastUser := PQ.LogUser as chgUser 

這就像在做一個循環下面的僞碼每個記錄(這已經是連續由同一人及彼等各自的日誌時間排序做

FOR EACH ROW IN RESULT SET 
    Set a flag "SameUser" = 1 if the value of the @lastUser is the same 
    as the current person record we are looking at 

    if the last user is the same as the previous record 
     use the @lastTime field as the "lastChange" column 
    else 
     use the @ignore field as the last change column 

    Now, build another flag based on the current record create time 
    and whatever the @lastTime value is based on a 20 minute interval. 
    set it to 1 if AT LEAST the 20 minute interval has been meet. 

    Now the key to the cycling the next record. 
    force the @lastTime = current record create_time 
    force the @lastUser = current user 
END FOR LOOP 

所以,如果你有以下作爲prequery的結果...(留下日期部分off)爲比爾

create status user sameuser lastchange 20minFlag carry to next row compare 
07:34 online Bill  0  09:05  0   07:34 Bill 
07:52 idle  Bill  1  07:34  0   07:52 Bill 
08:16 online Bill  1  07:52  1   08:16 Bill 
07:44 online Mark  0  09:05  0   07:44 Mark 
07:37 idle  Monica 0  09:05  0   07:37 Monica 
08:03 online Monica 1  07:37  1   08:03 Monica 

通知第一個記錄。因爲在他之前沒有人,所以標誌相同的用戶= 0。最後一次更改是9:05(創建sqlvars變量時通過NOW()),但是請查看「carry to next row compare」。在根據需要比較當前行之後,這將設置@lastTime和@lastUser。

Bill的下一行。它看到他與上一個用戶的上一行相同,所以SameUser標誌設置爲1.現在我們知道,我們有一個很好的「上次時間」來比較當前記錄「創建時間」。因此,從7點34分到7點52分是18分鐘,比我們20分鐘的時間間隔短20分鐘,因此我們保留了現在的7:52和比爾的第三排。

比爾的第三排。仍爲同一用戶(標誌= 1),最後更改爲7:52而不是現在8:16,我們有24分鐘...所以20分鐘標誌= 1。保留8:16和Bill作爲下一行。

馬克的第一行。自上次用戶爲Bill以來,Same User = 0。使用相同的9:05忽略時間並且不關心20分鐘的標誌,但是現在保存7:44並且標記爲下一行比較。

對莫妮卡。與Mark不同,所以SameUser = 0等與Bill完成相似。

所以,現在我們已經考慮了所有的塊和行。現在,將所有這些包裝起來並作爲查詢的「FinalAlias」,我們所做的就是爲「SameUser = 1」應用WHERE子句並且已經達到「20分鐘標記」。

您可以根據需要去掉最後一列的列表,並刪除where子句查看結果,但一定要爲name/create_time添加一個外部ORDER BY子句,以查看類似的模式,就像我在這裏一樣。