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

Hri*_*dar 26 postgresql production ruby-on-rails-3.1

我在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
Run Code Online (Sandbox Code Playgroud)

Cra*_*ger 43

如果user_idPRIMARY KEY,那么你需要升级PostgreSQL; 较新的版本将通过主键正确处理分组.

如果user_id既不是唯一的也不是所讨论的'estates'关系的主键,那么这个查询没有多大意义,因为PostgreSQL无法知道为多行共享相同内容的每一列返回哪个值.您必须使用表达你想要的东西,像一个聚合函数,,,,,等或感兴趣的列(S)添加到.estatesuser_idminmaxavgstring_aggarray_aggGROUP BY

或者你可以改写使用查询DISTINCT ONORDER BY如果你确实想挑一个有点乱排,虽然我真的怀疑它可能表达通过ActiveRecord的.

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

如果你有:

col1    col2
fred    42
bob     9
fred    44
fred    99
Run Code Online (Sandbox Code Playgroud)

你也是:

SELECT col1, col2 FROM mytable GROUP BY col1;
Run Code Online (Sandbox Code Playgroud)

那么很明显你应该得到这一行:

bob     9
Run Code Online (Sandbox Code Playgroud)

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

SELECT col1, max(col2) AS max_col2 FROM mytable GROUP BY col1;
Run Code Online (Sandbox Code Playgroud)


Jin*_*Lee 16

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

优雅的PostgreSQL Group for Ruby on Rails/ActiveRecord

这样,您可以获得所选列中与其他查询条件匹配的每个唯一值的一条记录:

MyModel.where(:some_col => value).select("DISTINCT ON (unique_col) *") 
Run Code Online (Sandbox Code Playgroud)

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


hec*_*hec 6

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

@problems = Problem.select('problems.username, sum(problems.weight) as weight_sum').group('problems.username').order('problems.username')
Run Code Online (Sandbox Code Playgroud)

  • 我有相同的(default_scope命令我的模型).所以我做的是:`Model.reorder(nil).group_by(...)`这样就删除了订单. (5认同)

Hri*_*dar 3

@myestate1 = Estate.where(:Mgmt => current_user.Company)
@myestate = @myestate1.select("DISTINCT(user_id)")
Run Code Online (Sandbox Code Playgroud)

这就是我所做的。