Rails 3:.group() 按created_at 排序
Rails 3 在 Activerecord 中排序 .group() 结果的方式是什么(此处为“created_at”)?
@messages = Message.group(:foo)
只会显示最旧的消息。我需要显示最新的。
我尝试过
@messages = Message.group(:foo).having("created_at = MAX(created_at)")
但没有成功。任何提示表示赞赏!
澄清一下:我希望让组在其内部排序,而不是正常的 messages.order("...")。 如果没有简单的 Activerecord 语法,我也会对原始 SQL 感到满意
更新:尝试 SQL 方式,这应该可以工作:
@messages = Message.find_by_sql("
SELECT messages.*
FROM messages
GROUP BY messages.foo
HAVING messages.created_at = MAX(messages.created_at)
ORDER BY messages.created_at DESC")
但这仅检索单个记录(未分组的记录)。据说分组的被省略了。不知道为什么,所有记录都有 :created_at 和 :foo 值
What is the Rails 3 way to order .group() results in Activerecord (here by "created_at")?
@messages = Message.group(:foo)
only results in displaying the oldest message. I'd need the latest to be shown.
I tried
@messages = Message.group(:foo).having("created_at = MAX(created_at)")
with no success. Any hints appreciated!
To clarify: I'm looking to have the group ordered within itself, not a normal messages.order("...").
Should there be no easy Activerecord syntax, i'd be happy with raw SQL as well
Update: trying the SQL way, this was supposed to work:
@messages = Message.find_by_sql("
SELECT messages.*
FROM messages
GROUP BY messages.foo
HAVING messages.created_at = MAX(messages.created_at)
ORDER BY messages.created_at DESC")
But this retrieves solely single records (those that are not grouped). Supposedly grouped ones are being omitted. Do not know why, all records have :created_at and :foo values
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
在某些数据库下,您无法使用 order 然后在同一查询中进行分组,因此您需要使用两个查询来完成此操作:
注意:这假设您有一个自动递增的
id
列,大多数 Rails 表都会这样做。You can't use order then group in the same query under some databases, so you need to do it using two queries:
Note: this assumes that you have an auto-incremented
id
column, which most Rails tables do.你可以使用 SQL,但你也可以大部分时间停留在 activerecord 领域,使用
postgres 的
DISTINCT ON ()
语法。 MYSQL 中有类似但略有不同的语法。我认为这个查询最终也会比接受的答案更有效,因为它只是一次排序和扫描,而不是 N 次排序。
You can go SQL, but you can also mostly stay in activerecord land with
The
DISTINCT ON ()
syntax is postgres. There's a similar but slightly different syntax in MYSQL.I think this query will end up being a lot more efficient, too, than the accepted answer because it's just a single sort and scan, instead of N sorts.
通过使用更专用的子查询来实现一切,无需 GROUP BY 调用:
这一切都归功于 Chaos 在该线程中的回答: 选择其中一列的值不同的 3 个最新记录
不过,尚不知道任何速度影响。如果有人想介入,请随意这样做。
Got it all working by using a more dedicated subquery, without a GROUP BY call:
All thanks to Chaos' answer in this thread: Select the 3 most recent records where the values of one column are distinct
Don't know about any speed implications yet though. If anyone wants to step in, please feel free to do so.
我刚刚遇到了同样的问题。以下 Rails 查询对我有用:
这里我们使用子查询来获取每个组中最大的(因此也是最新的)ID,然后过滤这些 ID 以仅显示状态 == '未读' 的 ID。
提示:我在 Message 模型类中创建了一个 self.latest 方法,其中包括:
这意味着我可以在控制器中使用它,如下所示:
I have just come across this same problem. The following Rails query worked for me:
Here we use a sub-query to get the largest (and therefore most recent) ID in each group, and then filter those to only show ones where state == 'unread'.
Tip: I made a self.latest method in my Message model class that consisted of:
Which meant I could use it in controllers like this:
我不明白如何使用 Arel 轻松地完成此操作 - 但如果您只是像在问题中那样构建自己的 SQL,则按如下方式修改它:
注意 HAVING 子句中的子查询。您的 HAVING 子句计算了所有消息的 MAX - 而不是仅计算 foo 中的消息。子查询应该可以解决这个问题。
我将消息表名称别名为 sub_messages - 但这不是必需的。我这样做只是为了“展示”父查询和子查询如何协同工作。
I don't see how this would be done using Arel easily - but if you just go with constructing your own SQL like you did in your question, then amend it as follows:
Note the subquery in the HAVING clause. Your HAVING clause calculated the MAX across all your messages - as opposed to only the messages within foo. The subquery should solve that problem.
I aliased the messages table name to sub_messages - but that shouldn't be necessary. I just did it to 'show' how the parent and subquery work together.