PostgreSQL必须出现在GROUP BY子句中,或者用在聚合函数中

时间:2013-08-05 14:55:54

标签: postgresql ruby-on-rails-3.1 production

我在pg生产模式下遇到此错误,但在sqlite3开发模式下工作正常。

 ActiveRecord::StatementInvalid in ManagementController#index

PG::Error: ERROR:  column "estates.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT "estates".* FROM "estates"  WHERE "estates"."Mgmt" = ...
               ^
: SELECT "estates".* FROM "estates"  WHERE "estates"."Mgmt" = 'Mazzey' GROUP BY user_id

@myestate = Estate.where(:Mgmt => current_user.Company).group(:user_id).all

4 个答案:

答案 0 :(得分:42)

如果user_id PRIMARY KEY ,则需要升级PostgreSQL;较新的版本将通过主键正确处理分组。

如果user_id既不是唯一的 也不是 有关'estates'关系的主键,那么此查询没有多大意义,因为PostgreSQL没有办法知道要为estates的每一列返回哪个值,其中多行共享相同的user_id。您必须使用表达所需内容的聚合函数,例如minmaxavgstring_aggarray_agg等,或添加列(s )GROUP BY感兴趣的。

或者,您可以将查询重新设置为使用DISTINCT ONORDER BY,如果您确实想要选择一些有意义的行,但我真的怀疑是否可以通过ActiveRecord来表达。

一些数据库 - 包括SQLite和MySQL--将只选择一行。 PostgreSQL团队认为这是不正确和不安全的,因此PostgreSQL遵循SQL标准并认为此类查询是错误的。

如果你有:

col1    col2
fred    42
bob     9
fred    44
fred    99

你做了:

SELECT col1, col2 FROM mytable GROUP BY col1;

然后很明显你应该得到一行:

bob     9

但是fred的结果怎么样?没有一个正确的答案可供选择,因此数据库将拒绝执行此类不安全的查询。如果您希望任何col2最佳 col1,您可以使用max聚合:

SELECT col1, max(col2) AS max_col2 FROM mytable GROUP BY col1;

答案 1 :(得分:15)

我最近从MySQL迁移到PostgreSQL并遇到了同样的问题。仅供参考,我发现的最佳方法是使用DISTINCT ON,如本SO答案所示:

Elegant PostgreSQL Group by for Ruby on Rails / ActiveRecord

这将让您为所选列中的每个唯一值获取一条记录,该记录与其他查询条件匹配:

MyModel.where(:some_col => value).select("DISTINCT ON (unique_col) *") 

我更喜欢DISTINCT ON,因为我仍然可以获取行中的所有其他列值。仅DISTINCT将仅返回该特定列的值。

答案 2 :(得分:6)

经常自己收到错误后,我意识到Rails(我使用的是rails 4)会自动添加一个'命令。在分组查询结束时。这通常会导致上述错误。因此,请确保在Rails查询结束时附加自己的.order(:group_by_column)。因此,你会有这样的事情:

@problems = Problem.select('problems.username, sum(problems.weight) as weight_sum').group('problems.username').order('problems.username')

答案 3 :(得分:3)

@myestate1 = Estate.where(:Mgmt => current_user.Company)
@myestate = @myestate1.select("DISTINCT(user_id)")

这就是我所做的。