Railsで直接SQLを実行していい感じに値を得る
ActiveRecordでSQLのクエリーを構築していくのは手軽でいいのですが、ちょっと特殊なことをしたいときはなかなかそれだけでは難しいかできない、ということがまれによくあります。
私もここ数日あれこれ試行錯誤した結果諦めたものがあります。どんなものかというと、
テーブルを内部結合してある条件に一致したレコードを、あるカラムについてグルーピングしてまた別のカラムで平均を求め、その平均がしきい値以上のものを取り出す
です。SQLだと、
select b.*, c.average from b, (select a.b_id, AVG(a.value) as average from a where a.type = 1 group by a.b_id) as c where b.id = c.b_id and c.average > 1
みたいなかんじになります。
平均を求めるところまではよかったのですが、そこから先がうまく行きませんでした*1。averageで平均を求めてグループ化すると、ActiveRecord::RelationではなくてActiveSupport::OrderedHashが返ってくるのでwhereを繋げられないようです。SQLならだいたい思い通りにかけそうだし、今回はSQLインジェクションの心配もないため*2、直接打ち込んでもよかろう、と思って調べることにしました。そしたらすぐに見つかりました。
ActiveRecord::ConnectionAdapters::DatabaseStatements
これを使って
ActiveRecord::Base.connection.select "select b.*, c.average from b, (sele(以下略)"
と打ち込んでやると結果がハッシュの配列で返ってきます。これだよ求めていたのは…!
参考
【Rails】ActiveRecord経由せずにsql直接実行する方法がたくさんあるの知らなかった… - 記すに足らず。
ありがとうございます。