我有一个小部件模型。小部件属于 Store 模型,Store 模型属于 Area 模型,Area 模型属于 Company。在公司模型中,我需要找到所有关联的小部件。简单的:
class Widget < ActiveRecord::Base
def self.in_company(company)
includes(:store => {:area => :company}).where(:companies => {:id => company.id})
end
end
这将生成这个漂亮的查询:
> Widget.in_company(Company.first).count
SQL (50.5ms) SELECT COUNT(DISTINCT "widgets"."id") FROM "widgets" LEFT OUTER JOIN "stores" ON "stores"."id" = "widgets"."store_id" LEFT OUTER JOIN "areas" ON "areas"."id" = "stores"."area_id" LEFT OUTER JOIN "companies" ON "companies"."id" = "areas"."company_id" WHERE "companies"."id" = 1
=> 15088
但是,我稍后需要在更复杂的范围中使用这个范围。问题在于 AR 通过选择单个字段来扩展查询,这在 PG 中失败,因为所选字段必须位于 GROUP BY 子句或聚合函数中。
这是更复杂的范围。
def self.sum_amount_chart_series(company, start_time)
orders_by_day = Widget.in_company(company).archived.not_void.
where(:print_datetime => start_time.beginning_of_day..Time.zone.now.end_of_day).
group(pg_print_date_group).
select("#{pg_print_date_group} as print_date, sum(amount) as total_amount")
end
def self.pg_print_date_group
"CAST((print_datetime + interval '#{tz_offset_hours} hours') AS date)"
end
这是它向 PG 抛出的选择:
> Widget.sum_amount_chart_series(Company.first, 1.day.ago)
SELECT "widgets"."id" AS t0_r0, "widgets"."user_id" AS t0_r1,<...BIG SNIP, YOU GET THE IDEA...> FROM "widgets" LEFT OUTER JOIN "stores" ON "stores"."id" = "widgets"."store_id" LEFT OUTER JOIN "areas" ON "areas"."id" = "stores"."area_id" LEFT OUTER JOIN "companies" ON "companies"."id" = "areas"."company_id" WHERE "companies"."id" = 1 AND "widgets"."archived" = 't' AND "widgets"."voided" = 'f' AND ("widgets"."print_datetime" BETWEEN '2011-04-24 00:00:00.000000' AND '2011-04-25 23:59:59.999999') GROUP BY CAST((print_datetime + interval '-7 hours') AS date)
这会产生此错误:
PGError:错误:列
“widgets.id”必须出现在
GROUP BY 子句或用于
聚合函数第 1 行:选择
“小部件”。“id”AS t0_r0,
“小部件”。“user_id...
如何重写 Widget.in_company 范围,以便 AR 不会扩展选择查询以包含每个 Widget 模型字段?