ActiveRecordでwhere 複数カラム in サブクエリを実装する
公開日:
更新日:
簡単にできそうでなかなか苦労したのでメモしておきます。
素のSQLに近い状態で書くのはそれほど難しくなさそうだったのですが、なんとなくActiveRecordを使って実装した方が…と思ってやってみました。
やりたいこととしては、たとえばこのようなuser_eventsというテーブルがあった場合に、ユーザーごとの最初のイベントのレコードのみを取り出したいという状況です。
SELECT * FROM `user_events` WHERE (`user_id`, `event_date`) IN (SELECT `user_id`, min(`event_date`) AS `min_event_date` FROM `user_events` GROUP BY `user_id`);
で、こんなデータを取り出したいというイメージです。
こちらですが、このように記述しました。
元々書いていた方法(記事下部に残しています)は、やはりパフォーマンス的に問題になるのでは?というところで、お仕事仲間から教えてもらいました
sub_query = UserEvents.group(:user_id) .select('user_id') .select('min(`event_date`) AS `min_event_date`') UserEvents.where("(`user_id` , `event_date`) IN (#{sub_query.to_sql})")
—– 以下、以前紹介していた方法 —–
sub_query = UserEvents.group(:user_id).select(:user_id, 'min(event_date) as min_event_date') sub_query.to_a.map do |sub_record| UserEvents.where(user_id: sub_record['user_id']).where(event_date: sub_record['min_event_date']) end.reduce(&:or)
これにより、where 複数カラム in サブクエリの部分が項目ごとにandとorでつなぎ合わされるので、望むような結果を得ることができます。
ただ、サブクエリで抽出されるレコード数が多い場合はちょっとどうなるのか心配ですが。。