Arel 中的嵌套查询
我尝试在 Rails 3 中的 Arel 和/或 Active Record 中嵌套 SELECT 查询以生成以下 SQL 语句。
SELECT sorted.* FROM (SELECT * FROM points ORDER BY points.timestamp DESC) AS sorted GROUP BY sorted.client_id
可以通过这样做创建子查询的别名
points = Table(:points)
sorted = points.order('timestamp DESC').alias
,但随后我陷入了如何将其传递到父查询中的困境(没有调用#to_sql
,这听起来相当难看)。
如何在 Arel(或 Active Record)中使用 SELECT 语句作为子查询来完成上述任务?也许有一种完全不同的方法来完成这个不使用嵌套查询的查询?
I am attempting to nest SELECT queries in Arel and/or Active Record in Rails 3 to generate the following SQL statement.
SELECT sorted.* FROM (SELECT * FROM points ORDER BY points.timestamp DESC) AS sorted GROUP BY sorted.client_id
An alias for the subquery can be created by doing
points = Table(:points)
sorted = points.order('timestamp DESC').alias
but then I'm stuck as how to pass it into the parent query (short of calling #to_sql
, which sounds pretty ugly).
How do you use a SELECT statement as a sub-query in Arel (or Active Record) to accomplish the above? Maybe there's an altogether different way to accomplish this query that doesn't use nested queries?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
虽然我不认为这个问题需要嵌套查询,就像 Snuggs 提到的那样。对于那些确实需要嵌套查询的人。这是我到目前为止所做的工作,虽然不是很好,但很有效:
Although I don't think this problem needs nested queries, like Snuggs mentioned. For those who do need nested queries. This is what I got working so far, not great but it works:
为了在“纯”Arel 中做到这一点,这对我有用:
当然,在你的情况下,点和排序将从点模型中检索和定制,而不是像上面那样制造。
To do this in "pure" Arel, this worked for me:
Of course, in your case, points and sorted would be retrieved and tailored from the Points model as opposed to manufactured as above.
这是我对临时表和 Arel 的处理方法。它使用 Arel#from 方法通过 Arel#to_sql 传入内部查询。
现在你可以使用outer_query、paginate、select、group等做一些不错的事情...
inner_query ->
外部查询->
Here's my approach to temporary tables and Arel. It uses Arel#from method passing in the inner query with Arel#to_sql.
Now you can do some nice things with the outer_query, paginate, select, group, etc...
inner_query ->
outer_query ->
问题是为什么需要“嵌套查询”?
我们不需要使用“嵌套查询”,这是以 SQL 而非关系代数的思维方式进行思考。通过关系代数,我们导出关系并使用一个关系的输出作为另一个关系的输入,因此以下内容成立:
除非绝对必要,否则最好将重命名为 arel。
这里 client_id 和时间戳的投影非常重要,因为我们无法投影关系中的所有域(即排序。*)。您必须专门投影将在关系的分组操作中使用的所有域。原因是 * 没有值可以明显代表分组的 client_id。例如,假设您有下表,
如果您进行分组,则无法在分数域上执行投影,因为该值可以是 27 或 69,但您可以投影总和(分数)
您只能投影具有唯一的域属性组的值(通常是聚合函数,如 sum、max、min)。对于您的查询,如果点按时间戳排序并不重要,因为最终它们将按 client_id 分组。时间戳顺序无关紧要,因为没有可以代表分组的单个时间戳。
请告诉我如何帮助您处理 Arel。另外,我一直在致力于让人们以 Arel 为核心的学习系列。该系列的第一篇位于 http://Innovative-Studios.com/#pilot
我可以告诉你,自从你使用 Table(:points) 而不是 ActiveRecord 模型 Point 以来,你已经开始知道如何做了。
The question is why would you need a "nested query"?
We do not need to use "nested queries" this is thinking in the mindset of SQL not Relational Algebra. With relational algebra we derive relations and use the output of one relation as input to another so the following would hold true:
It's best if we leave the renaming to arel unless absolutely necessary.
Here the projection of client_id AND timestamp is VERY important since we cannot project all domains from the relation (i.e. sorted.*). You must specifically project all domains that will be used within the grouping operation for the relation. The reason being is there is no value for * that would be distinctly representative of a grouped client_id. For instance say you have the following table
Here if you group you could not perform a projection on the score domain because the value could either be 27 or 69 but you could project a sum(score)
You may only project the domain attributes that have unique values to the group (which are usually aggregate functions like sum, max, min). With your query it would not matter if the points were sorted by timestamp because in the end they would be grouped by client_id. the timestamp order is irrelevant since there is no single timestamp that could represent a grouping.
Please let me know how I can help you with Arel. Also, I have been working on a learning series for people to use Arel at its core. The first of the series is at http://Innovative-Studios.com/#pilot
I can tell you are starting to know how to since you used Table(:points) rather than the ActiveRecord model Point.