Ruby on rails 带有PostgreSQL:GroupBy的Rails 3.1必须在聚合函数中使用
我正在尝试加载最新的10个艺术作品,这些作品按用户id分组,并按created_at订购。这在SqlLite和MySQL中运行良好,但在我的新PostgreSQL数据库中出现了一个错误Ruby on rails 带有PostgreSQL:GroupBy的Rails 3.1必须在聚合函数中使用,ruby-on-rails,ruby,postgresql,Ruby On Rails,Ruby,Postgresql,我正在尝试加载最新的10个艺术作品,这些作品按用户id分组,并按created_at订购。这在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 use
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...
有什么想法吗?看看这篇文章
PostGres实际上是在遵循SQL标准,而sqlite和mysql则打破了这一标准。看看这个问题-。Postgres不允许在不在group by子句中的select语句中列出列 表达式生成的sql不是有效的查询,您正在按
user\u id
进行分组,并在此基础上选择许多其他字段,但没有告诉DB应该如何聚合其他文件。例如,如果您的数据如下所示:
a | b
---|---
1 | 1
1 | 2
2 | 3
现在,当您要求db按a
分组并返回b时,它不知道如何聚合值1,2
。您需要告诉它是否需要选择最小值、最大值、平均值、总和或其他。就在我写答案的时候,有两个答案可以更好地解释这一切
不过,在您的用例中,我认为您不希望在db级别上使用GROUPBY。由于只有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],
# ....
# }
编辑:选择最新的艺术,但每个用户只能选择一种艺术
只是让您了解一下sql(由于我的系统上没有安装RDBMS,所以没有对其进行测试)
这个解决方案基于一个实际的假设,即同一用户的两个艺术作品不可能有相同的最高创作水平,但如果您导入或以编程方式创建大量艺术作品,则很可能是错误的。如果假设不成立,那么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])
您需要选择所需的特定列 艺术选择(:用户id).组(:用户id).限制(10) 例如,当您尝试在查询中选择标题时,它将引发错误 艺术选择(:用户id,:标题)。组(:用户id)。限制(10) 列“arts.title”必须出现在GROUP BY子句中,或在聚合函数中使用 这是因为当您尝试按用户id分组时,查询不知道如何处理组中的标题,因为组包含多个标题 因此,例外情况已经提到您需要按分组出现 艺术选择(:用户id,:标题)。组(:用户id,:标题)。限制(10) 或在聚合函数中使用 艺术选择(“用户id,数组集合(标题)作为标题”)。组(:用户id)。限制(10)
我有6000条记录,所以这可能会成为性能问题。我看到您有两条用户_id1的记录。我正在尝试加载最新的10件艺术品-只有一个公关用户。这不会是一个性能问题,直到你有一个限制条款10,但第二个问题仍然存在。我想可能会有原始sql来处理您想要的内容,但将其转换为Arel可能会很困难。更新了答案,但不确定其语法是否正确。让我知道这是否有效。你的例子有效。我有很多麻烦,让这个发挥与分页。这可以通过活动记录完成吗?这样您就可以调用.page(params[:page]).per(20)等方法。尝试将其转换为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])