两个关系的交叉点

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

@companies1 = Company.where(...) @companies2 = Company.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 

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

有两种情况:

 # 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 

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

 Company.where(...).all & Company.where(...).all 

当然,这样做会发出两个查询,并且很可能会查询比您需要的结果更多的结果。

使用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]) 

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

我这样解决类似的问题

 Company.connection.unprepared_statement do Company.find_by_sql "#{@companies1.to_sql} INTERSECT #{@companies2.to_sql}" end 

我们需要这里的precpared_statement块,因为最新的Rails版本使用预处理语句来加速arel查询,但我们需要纯SQL。

您可以使用ActiveRecord::SpawnMethods#merge

例:

 Company.where(condition: 'value').merge(Company.where(other_condition: 'value')) 

对于任何坚持使用Rails4并且无法使用Rails5。或语法的人:

我有一个动态数量的大查询,它们具有相似的条件(因此也有类似的结果)。 当我的rake服务器一次性实例化,转换为数组然后合并时,我的rake服务器就会出现问题。

我需要一个与find_each一起使用的ActiveRecord :: Relation(尚未解雇)。

看起来像这样:

 Class Conditions def initialize self.where_arr = [] self.joins_arr = [] end def my_condition1 where_arr << 'customers.status = "active"' joins_arr << :customer end def my_condition2 where_arr << 'companies.id = 1' end end conditions = [] joins = [] # probably call them in a .each block with .send conditions1 = Conditions.new conditions1.my_condition1 conditions1.my_condition2 conditions << "(#{conditions1.where_arr.join(' AND ')})" joins << conditions1.joins_arr conditions2 = Conditions.new conditions2.my_condition1 joins << conditions2.joins_arr Company.joins(joins).where(conditions.join(' OR ')) => SELECT companies.* FROM companies INNER JOIN customers ON companies.customer_id = customers.id WHERE (customers.status = 'active' AND companies.id = 1) OR (customers.status = 'active') 

它有点hacky但它​​可以工作,直到你可以希望迁移到Rails 5