3

「users」と「audit」という 2 つのテーブルがあり、ユーザーのステータスが変化するたびに、トリガーによって監査テーブルにデータが入力されるとします。両方のテーブルから選択し、関連する最新の監査エントリを使用してユーザー エントリ (一意) を取得しようとしています。テーブルに次のフィールドがあるとします。

ユーザー:

  • ID
  • ユーザー名
  • Eメール
  • 状態

監査:

  • id (任意の自動インクリメント)
  • user_id (fk)
  • new_status
  • created_at (これが発生した日時)

したがって、ユーザー エントリごとに、複数の監査エントリがあります。

したがって、最終的には結果を言う必要があります (イタリック体の部分は監査の結果であり、イタリック体以外は mysql 結果セットの行のユーザー部分です):
1 , john, john@gmail.com 、10、5、1、10、2012-08-10-10 : 15 :59
など

今、私が見ることができる唯一の方法は、次のような複合選択を行うことです: SELECT U.*, (SELECT * FROM audit A2 where A2.id = max(A.id)) FROM users U left join audit A on (U.id = A.user_id);

問題は、ユーザーに数千またはおそらく数十万の結果がある場合、DB で内部的に n+1 クエリを実行することになります。これは非常に非効率的です。

複合 SELECTS を使用せずに、これを 1 つの SQL ステートメントとして記述する方法についてのアイデアはありますか?

4

1 に答える 1

6

対応する監査エントリが常に存在すると想定しているため、INNERJOINを使用しました。created_atまた、同じユーザーに対して同じ日付の2つの監査エントリがないと仮定します。

select u.id, u.username, u.email, u.status, 
    a.id, a.new_status, a.created_at
from users u
inner join (
    select user_id, max(created_at) as MaxCreated
    from audit
    group by user_id
) am on u.id = am.user_id
inner join audit a on am.user_id = a.user_id and am.MaxCreated = a.created_at
于 2012-08-10T16:34:13.180 に答える