2013-01-16 30 views
1

我知道這是一個常見的問題,因爲我之前已經問過它,並且已經查看了更多,但儘管基於我的查詢,我仍然無法使其工作。見:Mysql join based on max(timestamp)mysql LEFT join for right table max valueMySQL - 左加入MAX時間戳

基本上我有一個不同的項目表('椅子','表'),並且每種類型都有自己的特定椅子或桌子的ID的記錄。然後我有一個位置表,它保留了所有曾經的位置,包括當前位置。當前位置由MAX時間戳記錄。

我的查詢是爲了獲取所有項目,並加入到當前位置。我遵循其他人所說的作品,但它不適合我。任何幫助表示讚賞。

編輯:我沒有說它是如何失敗的:它獲取記錄並進行連接,並返回最大時間戳,但不是與MAX(時間戳記錄)對應的記錄信息。所以它給出了正確的時間戳,但是發言權等不是來自具有MAX時間戳的記錄。

謝謝!

查詢:

$q = "SELECT 
     'chairs' AS work_type, 
     chairs.id AS work_id, 
     chairs.title, 
     chairs.dimensions, 
     CurrentLocations.floor, 
     CurrentLocations.bin, 
     CurrentLocations.bay, 
     CurrentLocations.other 
     FROM chairs 
      LEFT JOIN ( 
         SELECT 
           locations.id AS loc_id, 
           locations.work_type AS clwt, 
           locations.work_id AS clwi, 
           locations.floor, 
           locations.bin, 
           locations.bay, 
           locations.other, 
           MAX(locations.timestamp) AS latestLocation 
          FROM 
           locations 
          GROUP BY 
           locations.work_type, locations.work_id 
          ) CurrentLocations 
       ON CurrentLocations.clwi = chairs.id AND CurrentLocations.clwt = 'chairs' 
     WHERE cur_loc LIKE '%19th Street%' 
     ORDER BY 
      FIELD(floor, 'Basement', '3rd Floor', '4th Floor', '5th Floor'), 
      bin, 
      bay, 
      other"; 
+0

怎麼沒有工作,你得到了什麼錯誤?你得到錯誤的結果? –

+0

是的,對不起,這對我來說是無知的:它給出結果,但它選擇的位置記錄不是基於最新的時間戳。 – dgig

+0

首先,您通常應該通過GROUP BY給定SELECT子句中的每個未聚合字段。例如。 SELECT field1,field2,MAX(field3)FROM my_table GROUP BY field1,field2;此外,您的位置表看起來像需要正常化。 – Strawberry

回答

8

試試這個:

SELECT 
     'chairs' AS work_type,  -- do you really need this in the result? 
     c.id AS work_id, 
     c.title, 
     c.dimensions, 
     l.floor, 
     l.bin, 
     l.bay, 
     l.other 
    FROM 
     chairs AS c 
     LEFT JOIN 
     (SELECT work_id, 
       MAX(timestamp) AS latestLocation 
      FROM locations 
      WHERE work_type = 'chairs' 
      GROUP BY work_id 
     ) AS cl         -- CurrentLocations 
      ON cl.work_id = c.id 
     LEFT JOIN 
     locations AS l 
      ON l.work_type = 'chairs' 
      AND l.work_id = cl.work_id 
      AND l.timestamp = cl.latestLocation 
    WHERE 
     c.cur_loc LIKE '%19th Street%' 
    ORDER BY 
     FIELD(l.floor, 'Basement', '3rd Floor', '4th Floor', '5th Floor'), 
     l.bin, 
     l.bay, 
     l.other ; 

說明:

你想:

基本上我有不同的項目(chairstables)的表,每種類型都有記錄自己的ID爲特定的椅子或桌子。然後我有一個locations表,它保留了所有曾經的位置,包括當前的位置。當前位置由最大值timestamp指出。

我的查詢是爲了獲取所有項目(椅子),並加入到當前位置。

因此,對於每個項目(這是一個chair),你只想要最新location。對於表location中的每個work_id,您需要MAX(timestamp)。這可以用GROUP BY很容易被發現,因爲你已經發現:

 (SELECT work_id, 
       MAX(timestamp) AS latestLocation 
      FROM locations 
      GROUP BY work_type 
       , work_id 
     ) AS cl 

但你也想用從該表中的其他列,如果你只是在選擇列表中添加,它顯示錯誤的結果。 (請注意,在大多數DBMS中,爲了使用不在GROUP BY列表中的列,您必須應用聚合函數,就像您應用MAX()timestamp。MySQL允許這種行爲,如果使用得當,可以獲得一些好處。但是它沒有實現100%的失敗,因此在某些情況下應用它,像這樣,可能會給出錯誤的結果。Postgres有更好的實現這個功能,它不會允許錯誤的結果。)

所以,你要做的就是用上面的GROUP BY查詢作爲派生表什麼(你的名字clCurrentLocation,任何你想要的),並使用所有列從GROUP BY列表把它加入locations表,聚集的一個(timestamp):

 JOIN 
     locations AS l 
      ON l.work_type = cl.work_type 
      AND l.work_id = cl.work_id 
      AND l.timestamp = cl.latestLocation 

之後,你可以將他們加入到chairs表與往常一樣。因爲你在原始查詢中有一個chairs LEFT JOIN locations,所以我也將它們保留在答案中。

另一個小的修改是,因爲您有CurrentLocations.work_id = 'chairs',您只需要locations表中的那些行。因此,首先進行分組,然後拒絕不符合該條件的所有行是相當多餘的。首先應用條件然後按組合,可能會更高效。最終的分組查詢和連接條件相應地被修改。

另外請注意,上(work_type, work_id, timestamp)索引將提高查詢的效率(在cl子查詢將僅使用該索引來處理和JOIN locations將使用索引,也以定位從位置表所需的行。)

+1

就是這樣,謝謝。你能 - 如果你願意,你已經做得夠多了 - 有點描述這裏發生了什麼,有什麼不同?但這很棒,謝謝你。 – dgig

+0

感謝您的幫助和解釋。這非常有幫助。如果我能再次讓你高興,我會。 – dgig