Ruby on Rails 3如何使用“OR”条件?

50

我需要一条SQL语句来检查是否满足某个条件:

SELECT * FROM my_table WHERE my_table.x=1 OR my_table.y=1
我希望用“Rails3”的方式实现这个。我正在寻找类似以下的东西:
Account.where(:id => 1).or.where(:id => 2)

我知道我可以总是退而求其次使用SQL或条件字符串。然而,在我的经验中,当组合作用域时,这通常会导致混乱。有什么最好的方法可以做到这一点吗?

另一个相关的问题是,如何描述依赖于OR条件的关系。我找到的唯一方法是:

has_many :my_thing, :class_name => "MyTable",  :finder_sql => 'SELECT my_tables.* ' + 'FROM my_tables ' +
'WHERE my_tables.payer_id = #{id} OR my_tables.payee_id = #{id}'

然而,当它们组合使用时,这些方法再次出现了问题。有没有更好的方法来指定这个?

9个回答

113

Account.where(id: [1,2]) 不需要解释。


我见过最干净、最DRY的代码。干得好! - Eric Wanchic
11
太好了,而且非常简单。我也学到了你可以安全地使用 nil:例如 Thing.where(foo: [1, nil]) 会被翻译成 SELECT "things".* FROM "things" WHERE (("things"."foo" = 1 OR "things"."foo" IS NULL))。太棒了! - zkcro
但是例如,如果您使用“A不为空或A为空”,则无法使用此答案,但是您仍然可以在Rails 3中使用Account.arel_table [:id] .not_eq(nil).or()组合。 - Daniel Antonio Nuñez Carhuayo
喜欢这个解决方案。其他所有答案都太复杂了! - Ryan.lay
1
这是对另一个问题的回答。原始问题询问 my_table.x=1 OR my_table.y=1,其中 x 和 y 是表中不同的列。 - Josh
这仅适用于一个字段。 - Thomas

76

这在Rails 5中可以工作,请参见rails master

Post.where('id = 1').or(Post.where('id = 2'))
# => SELECT * FROM posts WHERE (id = 1) OR (id = 2)

对于 Rails 3.0.4+ 版本:

accounts = Account.arel_table
Account.where(accounts[:id].eq(1).or(accounts[:id].eq(2)))

5
我确实不喜欢这个语法,但是还是有趣的。 - DRobinson
我喜欢它,因为它可以组合。 - mdesantis

16

8
我会采用参数化的方式,建议您使用这种方式。Account.where("id = ? OR id = ?",1,2) - spyle
当使用简单数字时,我不认为有必要使用参数化值。 - David Morales
如果您正在硬编码ID,则简单数字就可以了,但我怀疑这些数字是从其他地方返回的,因此参数化是避免SQL注入的方法。 - Mark Davies
当然,正如第一位评论者所说,使用参数是一个好的方法。我只是写了硬编码数字作为示例。 - David Morales

9

很遗憾,.or还没有被实现(但是一旦实现,它将非常棒)。

所以你需要做类似这样的事情:

class Project < ActiveRecord::Base
  scope :sufficient_data, :conditions=>['ratio_story_completion != 0 OR ratio_differential != 0']
  scope :profitable, :conditions=>['profit > 0']

那样你仍然可以很棒,并且可以执行以下操作:
Project.sufficient_data.profitable

OR运算符尚未得到支持。它将按以下方式工作:users.where(users[:name].eq('bob').or(users[:age].lt(25))) - hjuskewycz

6

我建议使用 IN 子句,例如:

Account.where(["id in (?)", [1, 2]])

这是合适的,但请注意作者正在关注两个不同的领域... - Brian
哦,是的,这是真的。我根据这个语句Account.where(:id => 1).or.where(:id => 2)写出了答案。显然,它不适用于不同的字段。 - jpemberthy
2
如果数组中的一个值为 nil,则无法正常工作。假设您想要查找所有“viewed”为 falsenil 的记录,并且执行 Notification.where(:viewed => [false, nil]),它将无法正常工作,因为 MySQL 要求语法为 viewed = 0 OR viewed IS NULL,而不是 viewed = 0 OR viewed = NULLviewed IN (0, NULL) - Vikrant Chaudhary
Account.where(["id in (?)", [1, 2]]) 你忘记了 ( ? ) - antpaw

5
我使用了 Squeel gem (https://github.com/ernie/squeel/) 来进行 OR 查询,效果很好。
它让你可以将查询写成 Account.where{(id == 1) | (id == 2)} 的形式。

4
你可以在:conditions哈希中将数组定义为值。
例如,你可以这样做:
Account.all(:conditions => { :id => [1, 2] })

已验证适用于Rails 3.1.0


1
这是不高效的,因为您正在从数据库检索所有项目并在内存中进行检查。 - adrian.coroian

2

使用哈希表的备选语法

Account.where("id = :val1 OR id = :val2", val1: 1, val2: 2).

当值与多列进行比较时,这将特别有用。例如:

User.where("first_name = :name OR last_name = :name", name: 'tom')

1
使用 Rails,你可以这样做:
Account.where(id: 1).or(id: 2)

(它也适用于Rails 4和5.)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接