RailsでGROUP BYとORDER BYを組み合わせて使う

自社で開発しているRailsアプリでGROUP BYとORDER BYを組み合わせて使いたい場合があったので調べたことを共有したいと思います。

GROUP BYとORDER BYを併用する際の注意点

そもそもGROUP BYとORDER BYを普通に1つのクエリで実行すると思った結果がでません。

例えば以下のようなテーブルからauthor_idごとに一番古い記事のデータを取得するとします。

GROUP BYとORDER BYを使ってみると思ったような結果が返ってきません。

Googleで調べたところGROUP BYとORDER BYを併用すると、先にGROUP BYが実行されるため意図した結果とならないようです。

参考:MySQLでGROUP BYとORDER BYを同時に使用する場合に気をつけたいこと | 日記の間 | あかつきのお宿

サブクエリでORDER BYを優先実行

ではどうするかというとサブクエリを使います。

参考:[SQL] 7. サブクエリ 1 | TECHSCORE(テックスコア)

期待通りの結果になりました。

Railsでの実現方法

ではここからが本題でRailsでどうやって表現するか。

最初に思いついたのは find_by_sql で直にSQLを書く方法です。

ただ、これだとActiveRecordの便利な機能が全く使えなくなる( includes など)のでイマイチでした。

そこで色々と調べる内に ActiveRecord::QueryMethods に from というメソッドがあるということがわかりました。

参考:http://api.rubyonrails.org/v4.2.10/classes/ActiveRecord/QueryMethods.html#method-i-from

今回の例で言うと以下のような形になるかと思います。

先に、

の部分でORDER BYによる整列をしてから、

でGROUP BYするという流れになります。

これで思った通りの処理ができるようになりました。

APPENDIX

速度的な所はどうなのだろうと気になって調べてみる以下のような記事を見つけました。

参考:MySQL のサブクエリって、ほんとに遅いの? | Developers.IO

どうやらMySQLのバージョンが5.6以上であれば、それなりの速度が出るようです。

今回必要になった箇所については、そこまでのデータ件数ではなかったので、とりあえずはこの方法で行く予定ですが、パフォーマンスによっては別の方法を考える必要がでてきそうです。

まとめ

Railsって本当に便利ですよね!皆さんもぜひ上手にRailsを乗りこなして下さい。

スポンサードリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

This site uses Akismet to reduce spam. Learn how your comment data is processed.