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

时间:2012-12-18 12:31:49

标签: sql ruby-on-rails ruby postgresql heroku

我正在使用这种方法:

  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], ...]

3 个答案:

答案 0 :(得分:6)

你的错误是可能在默认范围内按顺序使用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上创建索引)。

答案 1 :(得分:3)

我想这是因为您在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")

答案 2 :(得分:1)

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

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