Kar*_*arl 8 postgresql activerecord ruby-on-rails
我有一个小部件模型.窗口小部件属于商店模型,属于区域模型,属于公司.在公司模型中,我需要找到所有相关的小部件.简单:
class Widget < ActiveRecord::Base
def self.in_company(company)
includes(:store => {:area => :company}).where(:companies => {:id => company.id})
end
end
Run Code Online (Sandbox Code Playgroud)
这将产生这个美丽的查询:
> 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
Run Code Online (Sandbox Code Playgroud)
但是,我后来需要在更复杂的范围内使用此范围.问题是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
Run Code Online (Sandbox Code Playgroud)
这是它在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)
Run Code Online (Sandbox Code Playgroud)
哪个会生成此错误:
PGError:错误:列"widgets.id"必须出现在GROUP BY子句中或用于聚合函数LINE 1:SELECT"widgets"."id"AS t0_r0,"widgets"."user_id ...
如何重写Widget.in_company范围,以便AR不扩展选择查询以包含每个Widget模型字段?
Den*_*rdy 10
正如Frank解释的那样,PostgreSQL将拒绝任何不返回可重现行集的查询.
假设您有一个类似的查询:
select a, b, agg(c)
from tbl
group by a
Run Code Online (Sandbox Code Playgroud)
PostgreSQL将拒绝它,因为b在group by语句中未指定.相比之下,在MySQL中运行它,它将被接受.但是,在后一种情况下,启动一些插入,更新和删除,并且磁盘页面上的行的顺序最终不同.
如果内存服务,实现细节是这样的,MySQL实际上将按a,b排序并返回集合中的第一个b.但就SQL标准而言,行为是未指定的 - 果然,PostgreSQL 在运行聚合函数之前并不总是排序.
这可能会导致bPostgreSQL中结果集的值不同.因此,除非你更具体,否则PostgreSQL会产生错误:
select a, b, agg(c)
from tbl
group by a, b
Run Code Online (Sandbox Code Playgroud)
Frank强调的是,在PostgreSQL 9.1中,if a是主键,而不是b未指定 - 当适用的主键意味着唯一的行时,计划程序已被教导忽略后续的分组字段.
特别是对于您的问题,您需要按照当前的方式指定您的组,以及您基于聚合的每个字段,即"widgets"."id", "widgets"."user_id", [snip]但不是类似的sum(amount),这些是聚合函数调用.
作为一个偏离主题的旁注,我不确定你的ORM /模型是如何工作的,但它生成的SQL并不是最佳的.许多左外连接似乎应该是内连接.这将导致计划员在适用的情况下选择适当的连接顺序.
| 归档时间: |
|
| 查看次数: |
1259 次 |
| 最近记录: |