ActiveRecordで複数のカラムの中から最大の値でソートする

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ActiveRecordで「複数のカラムの中から最大の値でソートしたい」というケースがありましたので、実装方法を紹介します。

例えば、Articleというモデルに、以下の2つのdatetime型のカラムがあるとします。

  create_table "articles", force: :cascade do |t|
    t.datetime "published_at"
    t.datetime "created_at"
  end

この2つのカラムのうち、大きい方の値でソートするには、以下のように書くことができます。

Article.select("articles.*, GREATEST(published_at, created_at) published_or_created_at")
       .order("published_or_created_at DESC")

発行されるSQLは以下のようになります。

SELECT articles.*, GREATEST(published_at, created_at) published_or_created_at FROM "articles" ORDER BY published_or_created_at DESC

このSQLはテーブルをフルスキャンしてしまうことに注意してください。実際に実装する場合は、ある程度の件数にまで絞り込みがされた状態で使うのが良いと思います。

また、もし published_or_created_at の値をアプリケーションの中でも参照したい場合、以下のようにモデルに attribute を追加することでアクセスすることもできます。(あまり実用的なアイディアではないですが。)

class Article < ApplicationRecord
  attribute :published_or_created_at, :datetime
end
Article.select("articles.*, GREATEST(published_at, created_at) published_or_created_at")
       .order("published_or_created_at DESC")
       .first
       .published_or_created_at

ご参考になれば幸いです。