Activerecord问题..如何优化此查询..
Prefectures (have many) Cities (have many) Shops (have many) Sales (have many) Brands
我想获得每个县的一个销售清单,这个清单还没有结束......然后列出销售中可用的品牌。
嵌套对我来说这很棘手!
这是我想出来的,虽然它非常丑陋&我认为它可以在查询级别进行优化,而不是获得所有未完成的销售。
#Get all sales which are yet to finish, ordered by finish date
upcoming_sales = Sale.includes([{:shop => {:city => :prefecture}}, :brands])
.where("finish > ?", Date.today)
.order('start ASC, finish ASC')
.select(['shop.city.prefecture.name', 'brands.name'])
#filter down to a single sale per prefecture
@sales = upcoming_sales.each_with_object({}){ |s,o|
o[s.shop.city.prefecture.name] = o[s.shop.city.prefecture.name] ||= s
}
答案 0 :(得分:2)
您可以获得即将到来的销售,然后加入商店=> cities =>都道府县和SELECT DISTINCT prefecture_id
这将确保每个县只有一次销售。像这样:
@sales = Sale.includes([{:shop => :prefecture},:brands])
.order('finish DESC')
.where("finish > ?", Date.today)
.joins(:shops => { :cities => :prefectures })
.select('sales.*, DISTINCT prefecture.id')
答案 1 :(得分:2)
这样的事情怎么样?
class Sale < ActiveRecord::Base
belongs_to :shop
has_many :brands
def self.first_sale_per_prefecture()
first_sale_id_per_prefecture = %(
select max(sales.id)
from sales
inner join shops on shop_id = shops.id
inner join cities on city_id = cities.id
where finish > #{Date.today}
group by prefecture_id
order by finish desc)
where("sales.id in (#{first_sale_id_per_prefecture})").includes(:brands, :shop => {:city => :prefecture})
end
end
答案 2 :(得分:0)
我将尝试使用Arel
class Sale < ActiveRecord::Base
belongs_to :shop
class << self
# Returns only Sale objects with obj.finish > today
# add on other ActiveRecord queries:
# Sale.unfinished.all
# Sale.unfinished.all :limit => 10
def unfinished
where(Sale.arel_table[:finish].gt(Date.today))
end
# should select only one set of unfinished sales,
# and where the prefecture name is distinct
def distinct_prefecture
Sale.unfinished.joins({:shop => {:city => :prefecture}}).where(Prefecture.arel_table[:name].distinct)
end
end
end
然后,你想要的地方:
@sales = Sale.distinct_prefecture \
.includes(:brands]) \ # should already include the other stuff with joins
.order('start ASC, finish ASC')
@brand_list = @sales.collect{|s| s.brands}
如果你想要一个有限的结果,这应该没问题:
@sales = Sale.distinct_prefecture \
.limit(10) \
.includes(:brands]) \
.order('start ASC, finish ASC')