3

我有Articles那个 have_many Metrics。当 Metric.name = "score" 时,我希望Articles按特定的 Metric.value 排序。(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模型具有确保 DESCending 排序的 default_scope。

  • 修复了“metrics.value DESC”报价位置的拼写错误。

  • 与我的电话朋友 uber rails 黑客交谈,看起来我可能需要一个原始 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")

感谢大家!

4

1 回答 1

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。此相关答案中使用的技术的更多解释:

不过,您似乎成为了一个非常基本的误解的受害者:

但我只对使用任何一篇文章的第一个(最近的)“分数”感兴趣。Metric 模型具有确保 DESCending 排序的 default_scope。

表格中没有“自然顺序”。在 aSELECT中,您需要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';
于 2013-05-06T01:30:39.920 回答