はじめに
Active Recordでは union
メソッドは提供されていません。ですが、運用上どうしても UNION したい場合はどうすればいいのか調査を行い培った知見をまとめます。
前提
- 以下の環境を利用します
Rails 7.0.3.1
Active Record 7.0.3.1
UNIONする方法
-
active_record_extended
gemをbundle install
する
https://github.com/GeorgeKaraszi/ActiveRecordExtended -
active_record_extended
gem で提供されているunion
メソッドを利用する
以下のように簡単にUNIONのSQLが発行できます。
irb(main):001:0> Author.union(Author.where(id: 2), Author.where(name: 'Yoko Sato'))
Author Load (3.6ms) SELECT "authors".* FROM (( (SELECT "authors".* FROM "authors" WHERE "authors"."id" = 2) UNION (SELECT "authors".* FROM "authors" WHERE "authors"."name" = 'Yoko Sato') )) authors
=>
[#<Author:0x000000010b5249a8
id: 2,
name: "Taro Yamada",
created_at: Mon, 14 Nov 2022 00:14:13.438430000 JST +09:00,
updated_at: Mon, 14 Nov 2022 00:14:13.438430000 JST +09:00>,
#<Author:0x000000010b5844c0
id: 3,
name: "Yoko Sato",
created_at: Mon, 14 Nov 2022 00:14:28.093465000 JST +09:00,
updated_at: Mon, 14 Nov 2022 00:14:28.093465000 JST +09:00>]
実行結果は where
メソッドと同じように ActiveRecord_Relation
で返ってくるので、通常のActive Recordの絞り込みや並び替えが使えるのがありがたいです。
irb(main):003:0> result.class
=> Author::ActiveRecord_Relation
active_record_extended gem の良い点
継続的にメンテナンスされている
CHANGELOGを見た限りでは、2019年5月から2022年8月まで継続的にメンテナンスされています。これからも引き続きメンテナンスされる印象です。
Ruby 3.1.x /Rails 7.0.xに対応
現時点(2022/11/15)で最新バージョンに対応しているので安心です。
PostgreSQLの拡張機能に対応している
標準のActive Recordが対応していないPostgreSQL固有の機能を使うことができ、用途によっては便利だと思います。
UNIONする他の方法はあるか
他にも以下の方法があります。
- 生SQLで書く
-
active_record_union gem を利用する
- ダウンロード数は1040万件と圧倒的に多いのですが、2018/01/14を最後に更新が停止やRailsのサポートバージョンが
5.2
と最新を追従できていませんでした。
- ダウンロード数は1040万件と圧倒的に多いのですが、2018/01/14を最後に更新が停止やRailsのサポートバージョンが
あるにはありましたが、安全性・長期的な利用を考えると現時点(2022/11/15)では active_record_extended
が良さそうでした。
まとめ
Active Recordを拡張するgemを利用して union を実現する方法を紹介しました。ただできればActive Recordの標準メソッドで union ができると一番ありがたいです。パフォーマンス的に問題なければ無理して union せずに or
メソッドでも良いと思います。どうしても UNION でないと実現できない・パフォーマンス的に良い場合は候補として検討してみてください。