两个关系的交叉点

ssc*_*rus 10 activerecord ruby-on-rails relation ruby-on-rails-3

假设我有两个在同一模型中保存记录的关系,例如:

@companies1 = Company.where(...)
@companies2 = Company.where(...)
Run Code Online (Sandbox Code Playgroud)

我怎样才能找到这两种关系的交集,即只有那两种关系中存在的公司?

Pet*_*ong 12

默认情况下将它们连接where在一起会创建AND,这就是您想要的.

这么多人是:

class Company < ActiveRecord::Base
  def self.where_1
    where(...)
  end
  def self.where_2
    where(...)
  end
end

@companies = Company.where_1.where_2
Run Code Online (Sandbox Code Playgroud)

======更新======

有两种情况:

# case 1: the fields selecting are different
Company.where(:id => [1, 2, 3, 4]) & Company.where(:other_field => true)
# a-rel supports &, |, +, -, but please notice case 2

# case 2
Company.where(:id => [1, 2, 3]) & Company.where(:id => [1, 2, 4, 5])

# the result would be the same as
Company.where(:id => [1, 2, 4, 5])
# because it is &-ing the :id key, instead of the content inside :id key
Run Code Online (Sandbox Code Playgroud)

因此,如果您遇到案例2,则需要像@apneadiving所评论的那样做.

Company.where(...).all & Company.where(...).all
Run Code Online (Sandbox Code Playgroud)

当然,执行此操作会发出两个查询,并且很可能会查询比您需要的结果更多的结果.

  • 这不会返回数组吗?如何让它返回ActiveRecord资源? (3认同)

Mik*_*iet 9

我以这种方式解决了类似的问题

Company.connection.unprepared_statement do
  Company.find_by_sql "#{@companies1.to_sql} INTERSECT #{@companies2.to_sql}"
end
Run Code Online (Sandbox Code Playgroud)

我们unprepared_statement在这里需要阻塞,因为最新的 Rails 版本使用准备好的语句来加速 arel 查询,但我们需要使用纯 SQL。


Mic*_*ael 5

使用sql关键字INTERSECT.

params1 = [1,2,4]
params2 = [1,3,4]
query = "
SELECT companies.* FROM companies
WHERE id in (?,?,?)
INTERSECT
SELECT companies.* FROM companies
WHERE id in (?,?,?)
"
Company.find_by_sql([query, *params1, *params2])
Run Code Online (Sandbox Code Playgroud)

它会比以前的解决方案更快.