MySQL LEFT JOIN使用MAX& GROUP BY在连接表上?

时间:2012-12-04 06:55:50

标签: mysql

我有两个表(成员和活动),我正在尝试使用每个成员的最新活动查询成员。我已经使用了两个查询(一个用于获取成员,第二个用max(id)和group by(成员)在活动上)和一些代码来合并数据。我确定它可以通过一个查询来完成,但我无法完成它。有什么想法吗?

会员表

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

3 个答案:

答案 0 :(得分:28)

"每组最新" 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子句将删除LEFT JOIN添加的行,从而有效地给出与原始INNER JOIN相同的结果。

但是如果在连接条件中应用附加谓词,则LEFT JOIN将按预期工作。

答案 1 :(得分: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

答案 2 :(得分: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