Rails / Postgres:“必须出现在GROUP BY子句中或用于聚合函数”

我正在使用这种方法:

def self.lines_price_report(n) Income.group('date(filled_at)').having("date(filled_at) > ?", Date.today - n).sum(:lines_price) end 

我在Heroku中收到此错误:

 PG::Error: ERROR: column "incomes.filled_at" must appear in the GROUP BY clause or be used in an aggregate function 

我怎样才能解决这个问题? 谢谢。

执行查询:

 SELECT SUM("incomes"."lines_price") AS sum_lines_price, date(filled_at) AS date_filled_at FROM "incomes" HAVING (date(filled_at) > '2012-12-04') GROUP BY date(filled_at) ORDER BY filled_at ASC 

预期结果

 [["2012-12-04", SUM_FOR_DATE], ["2012-12-05", SUM_FOR_DATE], ...] 

你的错误是可能在默认范围内按顺序使用filled_at。

您可以使用unscoped修复它以消除默认范围:

 Income.unscoped .group('date(filled_at)') .having("date(filled_at) > ?", Date.today - n) .sum(:lines_price) 

要么

 Income.unscoped .group('date(filled_at)') .having("date(filled_at) > ?", Date.today - n) .sum(:lines_price) .order('date(filled_at) ASC') 

但我认为更好的方法是使用而不是拥有

 Income.unscoped .where("date(filled_at) > TIMESTAMP ?", Date.today - n) .group('date(filled_at)') .sum(:lines_price) .order('date(filled_at) ASC') 

SQLFiddle

你必须小心使用TIMESTAMP,因为2012-12-04将成为2012-12-04 00:00:00所以如果你不希望这一天在结果中使用Date.today – (n – 1)

如果在filled_at列上创建索引

  create index incomes_filled_at on incomes(filled_at); 

移民:

  add_index :incomes, :filled_at 

并且你在这个表索引中有很多数据将用于过滤。 因此查询应该更快。

所以只需写两个并测试哪个更快(如果你没有,你必须在filled_at上创建索引)。

我想这是因为你在GROUP BY中使用了date(filled_at) ,但只是在ORDER中filled at 。 因为我猜订单来自默认范围,您需要通过reorder来覆盖它。 我会建议:

 Income.sum(:lines_price). group('date(filled_at)'). having("date(filled_at) > ?", Date.today - n). reorder("date(filled_at) ASC") 

如果要在PostgreSQL上使用Group By,则需要在group by上选择选项。

 Income.select('filled_at').group('date(filled_at)').having("date(filled_at) > ?", Date.today - n).sum(:lines_price)