何がしたいのか
例えば、usersテーブルがあり、それはアカウント情報だけを保持しているとする。そして、それを参照するテーブル、students、teachersがあるとする。それぞれ、生徒にしかない情報、先生にしかない情報を持っている。
この時、User一覧を取得する際に、StudentとTeacherの情報更新順にソートして出力したいとする。(StudentとTeacherには、情報更新日時を記録するupdated_atというカラムがある)
何が問題か
この場合、Railsのfind関数を使うと、次のようになる。
User.find(:all,:order => "・・・",:include => [:student,:teacher])
ここでorder_by句が問題になる。
order_by => "student.updated_at","teacher.updated_at"
としても、studentのupdatea_atでソートされて、その結果の中でteacherのupdated_at順にソートされるだけだ。両方のカラムをもつことはないので、結果、最初にstudentがずらりと並び、その後にteacherがずらりと並ぶ結果になる。
また、以下のようにやると、どちらのupdated_atなのか区別できず、ambiguousエラーが発生してしまう。
order_by => "updated_at"
解決策
解決策は、次のようになる。
StudentとTeacherは互いに独立しているので、1人のUserがこの2つの情報を同時に持つことはない。よって、students.updated_atとteachers.updated_atは必ず一方がnullになる。よって、order_by句は次のようになる。
order_by => "COALESCE(student.updated_at,teachers.updated_at)"
COALESCE関数は、引数の中に最初にでてくるnullで内値を返す。よって、このように指定すると、students.updated_atとteachers.updated_atを基準にソートが行なわれる。
ちなみに、MySQLで書くとこんな感じ。
mysql> select users LEFT OUTER JOIN students on users.id = students.user_id LEFT OUTER JOIN teahcers on users.id = teachers.user_id ORDER BY COALESCE(job_searchers.updated_at,recruiters.updated_at);