Rails 5: ActiveRecord OR 查询

113

如何在Rails 5 ActiveRecord中执行or查询?同时,是否可以在ActiveRecord查询中使用where链接or


5个回答

243
Rails 5中,可以将or条款与where条款链接在一起来进行ActiveRecord查询。请参阅相关讨论和Pull请求。因此,在Rails 5中,您可以执行以下操作:获取id为1或2的post
Post.where('id = 1').or(Post.where('id = 2'))

其他一些例子:

(A && B) || C:

    Post.where(a).where(b).or(Post.where(c))

(A || B) && C:

    Post.where(a).or(Post.where(b)).where(c)

3
我该如何获得 (A || B) && (C || D)。我尝试了 Post.where(a).or(Post.where(b)).where(c).or(Post.where(d)),但它的结果是:(A || B) && C || D。 - Imran Ahmad
3
@Imran 我认为应该是 Post.where(a).or(Post.where(b)).where(Post.where(c).or(Post.where(d))) 这样可以创建 (a || b) && (c || d)。 - engineersmnky
1
@Imran 这对我似乎不起作用:我得到了 ArgumentError: Unsupported argument type: #<MyModel::ActiveRecord_Relation:0x00007f8edbc075a8> (MyModel::ActiveRecord_Relation) - Suan
6
相当于 .or 并且生成 and 的是 .merge。可以通过 Post.where(a).or(Post.where(b)).merge(Post.where(c).or(Post.where(d))) 来生成 (A || B) && (C || D) - Siim Liiser
@SiimLiiser merge 是从哪里来的?如果是 Array#merge,那对我没用,因为我想要执行单个查询。而且还希望能够将整个内容作为关系传递。 - Mathieu J.
2
@MathieuJ。这是ActiveRecord :: Relation#merge。https://api.rubyonrails.org/classes/ActiveRecord/SpawnMethods.html#method-i-merge - Siim Liiser

14

我们不需要等到Rails 5才能使用这个OR查询,我们也可以在rails 4.2.3中使用它。有一个此处的后移版本。

感谢Eric-Guo提供的where-or宝石,现在我们可以使用这个宝石在>= rails 4.2.3中添加这个OR功能。


8
(对 K M Rakibul Islam 的答案进行补充。)使用作用域,代码可以变得更漂亮(取决于看的人的眼睛):
scope a,      -> { where(a) }
scope b,      -> { where(b) }

scope a_or_b, -> { a.or(b) }

5

我需要执行以下操作:(A && B) || (C && D) || (E && F)

但是在Rails 5.1.4的当前状态下,使用Arel或运算符链来实现这个操作变得太过复杂。但是我仍然想尽可能多地使用Rails来生成查询语句。

所以我进行了一个小小的hack:

在我的模型中,我创建了一个名为sql_where的私有方法:

private
  def self.sql_where(*args)
    sql = self.unscoped.where(*args).to_sql
    match = sql.match(/WHERE\s(.*)$/)
    "(#{match[1]})"
  end

下一步,我创建了一个数组来存储OR。
scope :whatever, -> {
  ors = []

  ors << sql_where(A, B)
  ors << sql_where(C, D)
  ors << sql_where(E, F)

  # Now just combine the stumps:
  where(ors.join(' OR '))
}

下面的查询语句可以得到预期的查询结果:

SELECT * FROM `models` WHERE ((A AND B) OR (C AND D) OR (E AND F))

现在,我可以轻松地将其与其他作用域组合使用,而不会产生错误的 OR 操作符。

优美之处在于,我的 sql_where 接受普通的 where 子句参数:sql_where(name: 'John', role: 'admin') 会生成 (name = 'John' AND role = 'admin')


我认为你可以使用.merge代替&&,并构建一个合适的树来捕获你的括号。像这样:(scopeA.merge(scopeB)).or(scopeC.merge(scopeD)).or(scopeE.merge(scopeF)),假设每个作用域看起来像Model.where(...) - nar8789
在使用合并之前,请查看此链接 - https://github.com/rails/rails/issues/33501 - Aarthi

1
Rails 5具备使用whereor语句的能力。 例如:
User.where(name: "abc").or(User.where(name: "abcd"))

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