no_picture

Ruby on Rails で NOT IN な SQL をかく。

Rails 4 で NOT な条件をもつ WHERE 句 が非常に書きやすくなりました。 Rails 4 なら NOT IN な SQL も簡単に書けます。 User.where.not( name: ["hoge","goro"] ) 条件にリストを渡せばよいです。SQLは以下のようになります。 SELECT "users".* FROM "users" WHERE ("users"."name" NOT IN ('hoge', 'goro')) サブクエリも使えます。これが便利すぎて困る。 query = User.select(:name) User.where.not name: query SELECT "users".* FROM "users" WHERE ("users"."name" NOT IN (SELECT name FROM "users")) Rails 3 の話 そうはいっても、Rails 4 にすぐには更新できないプロジェクトがあるので、これに慣れてしまうと非常につらい。折角なのでメモしておく。 where に文字列を渡す 格好悪いけど、とりあえずごまかす場合はこれを使う。 User.where("name NOT IN ('hoge', 'goro')") 文字列で渡す。 ? を使うとエスケープで泣きたくなるので、手軽には使えない。右辺も文字列で逃げます。 サブクエリを使うときは、こんな感じ。 query = User.select(:name) User.where("name NOT IN (#{query.to_sql})") SQLを直接書くしかない。複雑な query だとつらいので to_sql メソッドで逃げます。 squeel を使う Rails 3 だと NOT なSQL を書きづらいので、 squeel をよく使っています。 squeel を使っていればこんな風に書けます。 User.where { name << ["hoge","mogu"] } where に ブロックで引数が渡せるようになって << という演算子を使うと NOT IN になります。name はシンボルではないのも ポイントです。 ブロックで渡すので、スコープ内で name に値が束縛されているとそちらを参照してしまうので注意。 サブクエリも使える。素晴らしい。 query = User.select(:name) User.where { name << query } squeel を使うと LIKE やら OUTER JOIN やらもできます。便利。 arel の世界へ行く arel で構築した sql を where に渡す方法がある。 squeel をインストールしたくない時に。 users = User.arel_table User.where( users[:name].not_in(['hoge','mogu']) ) arel 自体あまり解説してる人がいないのでなかなか勉強しにくいのが欠点。 わかってくるとなんとなくでも書けます。 サブクエリもいけます。 query = User.select(:name) users = User.arel_table User.where( users[:name].not_in(query.arel) ) ActiveRecord::Relation はそのまま渡せませんが arel メソッドで変換可能です。 まとめ Rails 4 の not 便利です。 squeel も良いです.