Raf*_*ida 4 mysql activerecord ruby-on-rails ruby-on-rails-3
我真的想在活动记录的帮助下进行以下查询
(select *
from people p join cities c join services s
where p.city_id = c.id and p.id = s.person_id and s.type = 1)
intersect
(select *
from people p join cities c join services s
where p.city_id = c.id and p.id = s.person_id and s.type = 2)
Run Code Online (Sandbox Code Playgroud)
问题是,首先,mysql不支持交叉.但是,这可以解决.问题是我可以获得活动记录来输出甚至接近它的任何东西.
在活动记录中,我能做的最好的事情就是发出多个查询然后reduce :& 用来加入它们,但后来我得到一个数组,而不是一个关系.这对我来说是一个问题,因为我想调用限制等等.另外,我认为交叉点要由数据库完成,而不是ruby代码.
你的问题可能是没有交集的可解决的,例如:
Person.joins(:services).where(services: {service_type: [1,2]}).group(
people: :id).having('COUNT("people"."id")=2')
Run Code Online (Sandbox Code Playgroud)
但是,以下是我用于在ActiveRecord中构建交叉类似查询的一般方法:
class Service < ActiveRecord::Base
belongs_to :person
def self.with_types(*types)
where(service_type: types)
end
end
class City < ActiveRecord::Base
has_and_belongs_to_many :services
has_many :people, inverse_of: :city
end
class Person < ActiveRecord::Base
belongs_to :city, inverse_of: :people
def self.with_cities(cities)
where(city_id: cities)
end
def self.with_all_service_types(*types)
types.map { |t|
joins(:services).merge(Service.with_types t).select(:id)
}.reduce(scoped) { |scope, subquery|
scope.where(id: subquery)
}
end
end
Person.with_all_service_types(1, 2)
Person.with_all_service_types(1, 2).with_cities(City.where(name: 'Gold Coast'))
Run Code Online (Sandbox Code Playgroud)
它将生成以下形式的SQL:
SELECT "people".*
FROM "people"
WHERE "people"."id" in (SELECT "people"."id" FROM ...)
AND "people"."id" in (SELECT ...)
AND ...
Run Code Online (Sandbox Code Playgroud)
只要每个子查询在其结果集中返回匹配人员的id,您就可以根据任何条件/连接等使用上述方法根据需要创建任意数量的子查询.
每个子查询结果集将被AND在一起,从而将匹配集限制为所有子查询的交集.
UPDATE
对于那些使用AR4 scoped被删除的人,我的另一个答案提供了一个语义上等效的scopedpolyfil,all尽管AR文档建议,但它并不是等效的替代品.在这里回答:使用Rails 4,不推荐使用Model.scoped,但Model.all不能替换它
| 归档时间: |
|
| 查看次数: |
3049 次 |
| 最近记录: |