以has_many关系订购
我的Articles
有很多Metrics
。 当Metric.name =“得分”时,我希望通过特定的Metric.value来订购Articles
。 ( Metric
将各种文章统计信息记录为“名称”和“值”对。文章可以有多个度量标准,甚至多个“分数”,尽管我只对最近的排序感兴趣。)
class Article has_many :metrics class Metric # name :string(255) # value :decimal(, ) belongs_to :article
我正在努力写一个范围来做这个 – 任何想法? 像这样的东西?
scope :highest_score, joins(:metrics).order('metrics.value DESC') .where('metrics.name = "score"')
更新:
-
一篇文章可以在
metrics
量表中存储许多“分数”(因为它们是按周/每月/每年等计算的),但我只对使用任何一篇文章的第一个(最近的)“分数”感兴趣。Metric
模型具有default_scope,可确保DESCending排序。 -
修复了’metrics.value DESC’报价位置的拼写错误。
-
与我的手机朋友uber rails hacker交谈,看起来我可能需要一个原始的SQL查询。 现在,我已经超越了我的脑袋……(如果有帮助,我正在使用Postgres。)
谢谢!
更新2:
感谢Erwin的SQL查询建议,我有一个原始的SQL查询,它有效:
SELECT a.* FROM articles a LEFT JOIN ( SELECT DISTINCT ON (article_id) article_id, value FROM metrics m WHERE name = 'score' ORDER BY article_id, date_created DESC ) m ON m.article_id = a.id ORDER BY m.value DESC; article_list_by_desc_score = ActiveRecord::Base.connection.execute(sql)
这给出了一个表示文章数据的哈希数组(但不是文章对象??)。
后续问题:
有什么方法可以将它转换回Rails的activerecord查询? (所以我可以在范围内使用它)
解决方案更新:
如果有人正在寻找最终的ActiveRecord查询 – 非常感谢Mattherick帮我解决了这个问题 。 最终的工作查询是:
scope :highest_score, joins(:metrics).where("metrics.name" => "score").order("metrics.value desc").group("metrics.article_id", "articles.id", "metrics.value", "metrics.date_created") .order("metrics.date_created desc")
感谢大家!
查询可以像这样工作:
SELECT a.* FROM article a LEFT JOIN ( SELECT DISTINCT ON (article_id) article_id, value FROM metrics m WHERE name = 'score' ORDER BY article_id, date_created DESC ) m ON m.metrics_id = a.metrics_id ORDER BY m.value DESC;
首先 ,检索子查询m
每篇文章的name = 'score'
的“最新” value
。 在此相关答案中对使用的技术的更多解释:
- 选择每个GROUP BY组中的第一行?
你似乎成了一个非常基本的误解的受害者:
但我只对使用任何一篇文章中的第一个(最近的)“得分”感兴趣。 度量标准模型具有default_scope,可确保DESCending排序。
表中没有“自然顺序” 。 在SELECT
,您需要ORDER BY
定义良好的标准。 出于此查询的目的,我假设列metrics.date_created
。 如果您没有这种类型,则无法定义“最新”,并且被迫从多个符合条件的行中回退到任意选择:
ORDER BY article_id
这不可靠。 Postgres会挑选一排。 可能会随着表的任何更新或查询计划中的任何更改而更改。
接下来 , LEFT JOIN
到表article
和ORDER BY value
。 NULL
排序最后,所以没有限定值的文章最后。
注意:一些不那么聪明的ORM(我担心Ruby的ActiveRecord就是其中之一)使用非描述性和非独特的id
作为主键的名称。 您必须适应您未提供的实际列名称。
性能
应该体面。 就Postgres而言,这是一个“简单”的查询。 表metrics
部分多列索引会使其更快:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created) WHERE name = 'score';
按此顺序排列。 在PostgreSQL 9.2+中,您可以添加列值以使仅索引扫描成为可能:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created, value) WHERE name = 'score';