22

我有两个表(成员和活动),我正在尝试用每个成员的最新活动查询成员。我已经使用两个查询(一个获取成员,第二个使用活动的 max(id) 和 group by(member))和一些代码来合并数据。我确信它可以通过一个查询来完成,但我不能完全解决它。有任何想法吗?

成员表

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
4

3 回答 3

33

“每组最新”问题在 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)

你不需要分组。但是查询将分别受益于activitiesover(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 将按预期工作。

于 2012-12-04T07:54:20.263 回答
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
于 2012-12-04T07:23:43.530 回答
3
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
于 2012-12-04T07:03:18.047 回答