以has_many关系订购

时间:2013-05-05 08:06:28

标签: sql ruby-on-rails ruby-on-rails-3 postgresql activerecord

Articles有{_ 1}}。当Metric.name =“得分”时,我希望通过特定的Metric.value订购Metrics。 (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模型有一个default_scope,可确保DESCending排序。

  • 修正了'metrics.value DESC'报价位置的拼写错误。

  • 与我的手机朋友uber rails hacker交谈,看起来我可能需要一个原始的SQL查询。现在我已经超越了我的头脑......(如果有帮助,我正在使用Postgres。)

谢谢!

更新2:

感谢Erwin的SQL查询建议,我有一个原始的SQL查询可以运行:

Metric

它给出了一个表示文章数据的哈希数组(但不是文章对象??)。

后续问题:

任何将这个转换回Rails的activerecord查询的方法? (所以我可以在范围内使用它)

解决方案更新:

如果有人正在寻找最终的ActiveRecord查询 - 非常感谢Mattherick帮助我完成了question。最终的工作查询是:

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)

谢谢大家!

1 个答案:

答案 0 :(得分:3)

查询可以这样工作:

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;

首先,在子查询value中为每篇文章检索name = 'score'的“最新”m。在相关答案中对使用过的技术有更多解释:

你似乎成了一个非常基本的误解的受害者:

  

但我只对使用第一个(最近的)“得分”感兴趣   对于任何一篇文章。度量标准模型具有default_scope,可确保DESCending排序。

表格中有 no“自然顺序”。在SELECT中,您需要ORDER BY明确定义的标准。出于此查询的目的,我假设列metrics.date_created。如果您没有任何类型,那么无法定义“最新”并被迫从多个符合条件的行中回退到任意选择:

   ORDER  BY article_id

可靠。 Postgres会挑选一排。可能会随着表的任何更新或查询计划中的任何更改而更改。

下一步LEFT JOIN到表articleORDER BY valueNULL排序最后,所以没有限定值的文章最后一次。

注意:一些不那么聪明的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';