带有PostgreSQL的Rails 3.1:GROUP BY必须在聚合函数中使用

我正在尝试加载由user_id分组并由created_at排序的最新10种艺术。 这适用于SqlLite和MySQL,但在我的新PostgreSQL数据库上出错。

Art.all(:order => "created_at desc", :limit => 10, :group => "user_id") 

ActiveRecord错误:

 Art Load (18.4ms) SELECT "arts".* FROM "arts" GROUP BY user_id ORDER BY created_at desc LIMIT 10 ActiveRecord::StatementInvalid: PGError: ERROR: column "arts.id" must appear in the GROUP BY clause or be used in an aggregate function LINE 1: SELECT "arts".* FROM "arts" GROUP BY user_id ORDER BY crea... 

有任何想法吗?

表达式生成的sql不是有效查询,您按user_id进行分组,并根据该字段选择许多其他字段,但不告诉DB如何聚合其他文件。 例如,如果您的数据如下所示:

 a | b ---|--- 1 | 1 1 | 2 2 | 3 

现在当你要求db按a分组并且还返回b时,它不知道如何聚合值1,2 。 你需要告诉它是否需要选择min,max,average,sum或其他东西。 就在我写答案的时候,有两个答案可以更好地解释这一切。

但是在你的用例中,我认为你不希望在db级别上有一个组。 由于只有10种艺术,您可以将它们分组到您的应用程序中。 不要在成千上万的艺术中使用这种方法:

  arts = Art.all(:order => "created_at desc", :limit => 10) grouped_arts = arts.group_by {|art| art.user_id} # now you have a hash with following structure in grouped_arts # { # user_id1 => [art1, art4], # user_id2 => [art3], # user_id3 => [art5], # .... # } 

编辑:选择latest_arts,但每个用户只有一个艺术品

只是为了给你一个sql的想法(没有测试它,因为我没有在我的系统上安装RDBMS)

 SELECT arts.* FROM arts WHERE (arts.user_id, arts.created_at) IN (SELECT user_id, MAX(created_at) FROM arts GROUP BY user_id ORDER BY MAX(created_at) DESC LIMIT 10) ORDER BY created_at DESC LIMIT 10 

此解决方案基于实际假设,即同一用户的两种艺术不能具有相同的最高create_at,但如果您正在导入或以编程方式创建大量艺术,则可能是错误的。 如果假设不成立,那么sql可能会更加有条理。

编辑:尝试将查询更改为Arel:

 Art.where("(arts.user_id, arts.created_at) IN (SELECT user_id, MAX(created_at) FROM arts GROUP BY user_id ORDER BY MAX(created_at) DESC LIMIT 10)"). order("created_at DESC"). page(params[:page]). per(params[:per]) 

您需要选择所需的特定列

Art.select(:USER_ID)。集团(:USER_ID).limit(10)

例如,当您尝试在查询中选择标题时,它将引发错误

Art.select(:user_id,:title).group(:user_id).limit(10)

列“arts.title”必须出现在GROUP BY子句中或用于聚合函数

这是因为当您尝试按user_id分组时,查询不知道如何处理组中的标题,因为该组包含多个标题。

所以exception已经提到你需要出现在group by中

Art.select(:user_id,:title).group(:user_id,:title).limit(10)

或用于聚合函数

Art.select(“user_id,array_agg(title)as titles”)。group(:user_id).limit(10)

看看这篇postSQLite到Postgres(Heroku)GROUP BY

PostGres实际上遵循SQL标准,而sqlite和mysql违反了标准。

看看这个问题 – 将MySQL选择转换为PostgreSQL 。 Postgres不允许在select语句中列出不在group by子句中的列。