ゆうなんとかさんの雑記帳的な。

Twitterで踊ったり音ゲーしたりしてるあの名前がよくわからない人が書いてるらしいよ。

Railsで直接SQLを実行していい感じに値を得る

ActiveRecordSQLのクエリーを構築していくのは手軽でいいのですが、ちょっと特殊なことをしたいときはなかなかそれだけでは難しいかできない、ということがまれによくあります。
私もここ数日あれこれ試行錯誤した結果諦めたものがあります。どんなものかというと、

テーブルを内部結合してある条件に一致したレコードを、あるカラムについてグルーピングしてまた別のカラムで平均を求め、その平均がしきい値以上のものを取り出す

です。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(以下略)"

と打ち込んでやると結果がハッシュの配列で返ってきます。これだよ求めていたのは…!

*1:rails consoleで試しているときに結果が「{}」だけ表示されたときに無理っぽい予感はしてた

*2:固定のクエリしか使わない