ActiveRecord ORクエリ


181

Rails 3のActiveRecordでORクエリを行う方法を教えてください。私が見つけたすべての例には、ANDクエリしかありません。

編集:ORメソッドはRails 5以降で使用できます。ActiveRecord:: QueryMethodsを参照してください


7
SQLを学ぶ。ActiveRecordを使用すると、物事を簡単に機能させることができますが、クエリが何をしているかを知る必要があります。そうしないと、プロジェクトがスケーリングされない可能性があります。また、SQLを扱う必要がなくてもうまくいくと思っていましたが、それは非常に間違っていました。
ryan0 2013

1
@ ryan0、あなたはとても正しいです。私たちは派手な宝石やその他のものを使用することがありますが、これらの宝石が内部で何をしているのか、基礎となるテクノロジーは何かを認識している必要があります。パフォーマンス。宝石は特定の数のユースケースを念頭に置いて作成されますが、プロジェクトのユースケースの1つが異なる場合があります。
rubyprince 14

2
役立つかもしれません:ActiveRecord ORクエリハッシュ表記
ポタシン

1
:Railsの5ので、私見では受け入れ答えはグレッグ・オルセンのバージョンでなければなりませんPost.where(column: 'something').or(Post.where(other: 'else'))
フィリップ・Classenの

6
この質問にはruby-on-rails-3のタグが付いています。なぜ受け入れられた答えはRails 5にのみ関係するのでしょうか?
iNulty 2017

回答:


109

ARelを使用する

t = Post.arel_table

results = Post.where(
  t[:author].eq("Someone").
  or(t[:title].matches("%something%"))
)

結果のSQL:

ree-1.8.7-2010.02 > puts Post.where(t[:author].eq("Someone").or(t[:title].matches("%something%"))).to_sql
SELECT     "posts".* FROM       "posts"  WHERE     (("posts"."author" = 'Someone' OR "posts"."title" LIKE '%something%'))

少し乱雑に感じますが、少なくとも私はsqlを作成していません。さらにArelを使用する必要があります。
pho3nixf1re

55
Sequelがどれほどエレガントであるかを私は信じられません
マカリオ

3
SQLに問題はありません。うまくいかない可能性があるのは、SQL文字列、つまりSQL Injectionを構築する方法です。そのため、データベースに対して実行する必要があるSQLクエリに提供する前に、ユーザー入力を無害化する必要があります。これはORMによって処理され、これらは私たちが見落としがちなエッジケースを処理してきました。したがって、ORMを使用してSQLクエリを作成することを常にお勧めします。
rubyprince 2014年

5
SQLのもう1つの問題は、データベースに依存しないことです。例えば、matches生成されますLIKEsqliteの(デフォルトではケースの小文字を区別しない)のためにとILIKEpostgresの上(オペレータのような明示的なケース小文字を区別しないが必要です)。
amoebe 2015

1
@ToniLeigh ActiveRecordは内部でSQLを使用しています。これは、SQLサニタイズを処理し、クエリをDBに依存しないようにするSQLクエリを記述するための構文にすぎません。唯一のオーバーヘッドは、Railsが構文をSQLクエリに変換する場所です。そして、それはミリ秒の問題です。もちろん、最高のパフォーマンスのSQLクエリを記述して、それをActiveRecord構文に変換する必要があります。SQLをActiveRecord構文で表すことができない場合は、プレーンSQLを使用する必要があります。
rubyprince

208

1つの列の値にOR演算子を使用する場合は、配列をに渡す.whereと、ActiveRecordが使用しますIN(value,other_value)

Model.where(:column => ["value", "other_value"]

出力:

SELECT `table_name`.* FROM `table_name` WHERE `table_name`.`column` IN ('value', 'other_value')

これORにより、1つの列と同等の


13
これは最もきれいな「レールウェイ」回答であり、受け入れられるべき
でし

10
@koonseに感謝します。これは厳密には「OR」クエリではありません、この状況では同じ結果になります。
deadkarma 2013

-あなたができる場合は、ヘルプstackoverflow.com/questions/15517286/...
Pratik Bothra

80
この方法では2つの異なる列を使用できないため、このソリューションはORの代わりにはなりません。
fotanus 2014

152

Rails 3では、それは

Model.where("column = ? or other_column = ?", value, other_value)

これには未加工のSQLも含まれますが、ActiveRecordにOR操作を行う方法があるとは思いません。あなたの質問はnoobの質問ではありません。


41
生のSQLがあるとしても、この文はArelよりもはるかに明確に見えます。多分ドライヤー。
jibiel 2011

6
あなたがチェーンに必要な場合は、他のテーブルには、あなたがこのようにそれを使用する必要があり、同じ列名を持つ列を持っている可能性があります参加するPage.where("pages.column = ? or pages.other_column = ?", value, other_value)
rubyprince

1
そして、クエリがテーブルにエイリアスを設定すると失敗します。それがアレルの輝きです。
DGM 2014年

58

Rails / ActiveRecordの更新バージョンは、この構文をネイティブでサポートする場合があります。次のようになります。

Foo.where(foo: 'bar').or.where(bar: 'bar')

このプルリクエストに記載されているようにhttps://github.com/rails/rails/pull/9052

とりあえず、次のことを続けるだけでうまくいきます。

Foo.where('foo= ? OR bar= ?', 'bar', 'bar')

更新:https : //github.com/rails/rails/pull/16052によると、このor機能はRails 5で利用可能になる予定です。

更新:機能がRails 5ブランチにマージされました


2
orは現在Rails 5で利用できますが、1つの引数が渡されることを想定しているため、この方法では実装されません。Arelオブジェクトが必要です。承認された回答を見る
El'Magnifico

2
orActiveRecord のメソッドは、直接使用している場合は機能しますが、スコープ内で使用すると、期待どおりに動作しない可能性があります。
ジェレミーリスト

@JeremyListが言ったことはその場で。それは私を激しく噛んだ。
コートシマ



14

配列を引数として使用する場合、次のコードはRails 4で機能します。

query = Order.where(uuid: uuids, id: ids)
Order.where(query.where_values.map(&:to_sql).join(" OR "))
#=> Order Load (0.7ms)  SELECT "orders".* FROM "orders" WHERE ("orders"."uuid" IN ('5459eed8350e1b472bfee48375034103', '21313213jkads', '43ujrefdk2384us') OR "orders"."id" IN (2, 3, 4))

詳細:Rails 4の引数として配列を使用したORクエリ


9
またはこれ:Order.where(query.where_values.inject(:or))arelをずっと使うため。
Cameron Martin

> Rails 4の引数として配列を使用したORクエリ。便利なリンク!ありがとう!
Zeke Fast

7

MetaWhereプラグインは完全に素晴らしいです。

ORとANDを簡単に組み合わせ、任意の関連付けの条件を結合し、さらにOUTER JOINを指定することもできます。

Post.where({sharing_level: Post::Sharing[:everyone]} | ({sharing_level: Post::Sharing[:friends]} & {user: {followers: current_user} }).joins(:user.outer => :followers.outer}

6

条件にORを追加するだけです

Model.find(:all, :conditions => ["column = ? OR other_column = ?",value, other_value])

4
これはRails 2の構文であり、SQL文字列の少なくとも一部を記述する必要があります。
pho3nixf1re

3

スコープをと組み合わせることができるクライアントの作業からこのプラグインを抽出したところです.or.Post.published.or.authored_by(current_user)。Squeel(MetaSearchの新しい実装)も素晴らしいですが、ORスコープを許可しないため、クエリロジックは少し冗長になる可能性があります。


3

rails + arelを使用すると、より明確な方法:

# Table name: messages
#
# sender_id:    integer
# recipient_id: integer
# content:      text

class Message < ActiveRecord::Base
  scope :by_participant, ->(user_id) do
    left  = arel_table[:sender_id].eq(user_id)
    right = arel_table[:recipient_id].eq(user_id)

    where(Arel::Nodes::Or.new(left, right))
  end
end

生成する:

$ Message.by_participant(User.first.id).to_sql 
=> SELECT `messages`.* 
     FROM `messages` 
    WHERE `messages`.`sender_id` = 1 
       OR `messages`.`recipient_id` = 1

3

あなたはそれを次のようにすることができます:

Person.where("name = ? OR age = ?", 'Pearl', 24)

よりエレガントな場合は、rails_or gemをインストールして、次のようにします。

Person.where(:name => 'Pearl').or(:age => 24)

-2

これを追加したいのは、ActiveRecordの複数の属性を検索するソリューションです。以来

.where(A: param[:A], B: param[:B])

AとBを検索します。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.