2012-12-04 73 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