22

2 つのテーブル (メンバーとアクティビティ) があり、各メンバーの最新のアクティビティでメンバーをクエリしようとしています。2 つのクエリ (1 つはメンバーを取得するクエリ、もう 1 つはアクティビティの 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)

グループ化する必要はありません。ただし、クエリは、それぞれまたは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 は期待どおりに機能します。

于 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 に答える