2012-12-04 115 views
21

我有兩個表(成員和活動),我試圖查詢與每個成員的最新活動的成員。我有兩個查詢(一個獲取成員,第二個獲得max(id)和group(by member))以及一些合併數據的代碼。我確定它可以用一個查詢來完成,但我無法完成它。有任何想法嗎?在連接表上使用MAX&GROUP BY的MySQL LEFT JOIN?

成員表

id, name 
1, Shawn 
2, bob 
3, tom 

活動表

id, member_id, code, timestamp, description 
1,   1, 123,  15000, baked a cake 
2,   1, 456,  20000, ate dinner 
3,   2, 789,  21000, drove home 
4,   1, 012,  22000, ate dessert 

期望的結果:

id, name, activity_code, activity_timestamp, activity_description 
1, shawn, 012,   22000,    ate dessert 
2, bob, 789,   21000,    drove home 
3, tom, null,   null,    null 

回答

26

的「最新的每個組」的問題是極其常見於SQL中的。單就這個網站上的這個問題有無數的解決方案。

如果你的時間戳,每位會員活動潮頭:

SELECT 
    m.id, 
    m.name, 
    a.code activity_code, 
    a.timestamp activity_timestamp, 
    a.description activity_description 
FROM 
    members m 
    INNER JOIN activities a ON a.member_id = m.id 
WHERE 
    a.timestamp = (SELECT MAX(timestamp) FROM activities WHERE member_id = m.id) 

另外,如果您的活動ID與時間單調遞增:

... 
WHERE 
    a.id = (SELECT MAX(id) FROM activities WHERE member_id = m.id) 

你不需要組。但是,查詢將受益於activities上的索引分別超過(member_id, timestamp)(member_id, id)


編輯

顯示誰沒有登錄活動的任何成員,使用左連接這樣。

SELECT 
    m.id, 
    m.name, 
    a.code activity_code, 
    a.timestamp activity_timestamp, 
    a.description activity_description 
FROM 
    members m 
    LEFT JOIN activities a ON 
    a.member_id = m.id 
    AND a.timestamp = (SELECT MAX(timestamp) FROM activities WHERE member_id = m.id) 

請注意,沒有WHERE子句。在語義上,在連接完成後,WHERE被應用。因此,WHERE子句將刪除LEFT JOIN添加的行,實際上會給出與原始INNER JOIN相同的結果。

但是,如果在連接條件中應用附加謂詞權限,則LEFT JOIN將按預期工作。

+0

這似乎是我的成員(湯姆,id = 3)從未登錄任何activities.I嘗試改變內部聯接到左聯接。 我想第二個WHERE語句,我的時間戳不保證是唯一的,但ID是一個獨特的自動遞增字段。 –

+0

@ShawnMcBride請參閱修改後的答案。 – Tomalak

+0

我個人不喜歡條件中的嵌套查詢。如果你加入只有MAX時間戳的查詢,這將是更加優化的解決方案,比如下面的答案 – dzona

1
Select max(a.id), m.name, a.activity_code, a.activity_timestamp, a.activity_description 
From members m 
    Left join 
    activities a on a.member_id=m.id 
Group by m.name, a.activity_code, a.activity_timestamp, a.activity_description 
6
SELECT 
    members.id , 
    members.name, 
    activities.code AS activity_code, 
    activities.timestamp AS activity_timestamp, 
    activities.description AS activity_description 
FROM 
    members 
    LEFT JOIN activities 
     ON members.id = activities.member_id 
    LEFT JOIN 
     (
      SELECT 
       activities.member_id 
       MAX(activities.id) AS id 
      FROM activities 
      GROUP BY 
       activities.member_id 
     ) AS t1 
     ON activities.id = t1.id 
WHERE 
    t1.id IS NOT NULL 
+0

我想你應該在兩種情況下都使用左連接。 – Tomalak

+0

它似乎在放棄從未記錄任何活動的我的成員。我得到與Tomalak的查詢相同的結果。如果我將第二個JOIN更改爲LEFT JOIN,它似乎會返回所有活動記錄。 –

+0

@ShawnMcBride' WHERE t1.id IS NOT NULL' was missing。請再試一次。 – edze