Rails / ActiveRecord:我可以在不将SQL字符串传递给#order的情况下执行此查询吗?

问题描述 投票:1回答:1

我有两个型号IssueLabel。他们有很多关系。

我有一个方法返回指向最多问题的十个标签。

class Label < ApplicationRecord
  has_many :tags
  has_many :issues, through: :tags

    def self.top
        Label.joins(:issues)
        .group(:name)
        .order('count_id desc')
        .count(:id)
        .take(10)
    end
end

它完全符合我的预期,但我想知道是否可以在没有SQL字符串的情况下编写查询。

order('count_id DESC')令我困惑。 count_id来自哪里?没有名为count_id的列。

Label.joins(:issues).group(:name).column_names
#=> ["id", "name", "created_at", "updated_at"]

我发现了一些SQL示例here。我认为它与ORDER BY COUNT(Id)基本相同:

SELECT COUNT(Id), Country
FROM Customer
GROUP BY Country
ORDER BY COUNT(Id) DESC

是否可以在不传入SQL字符串的情况下执行相同的查询?可以单独使用ActiveRecord查询界面吗?

sql ruby-on-rails activerecord rails-activerecord
1个回答
1
投票

如果查看查询日志,您会看到如下内容:

select count(labels.id) as count_id ...

您的group调用(使用任何参数)和count(:id)调用的组合获取ActiveRecord以将count_id列别名添加到查询中。我不认为这是在任何地方记录或指定的(至少我可以找到),但如果你足够勇敢地通过Active Record源,你可以看到它发生。

通常,如果添加GROUP BY然后添加count(:x),Active Record将添加count_x别名。这里没有专栏,所以你不能说order(:count_id)order(count_id: :desc)或任何其他常见的非String替代品。 AFAIK,您必须使用字符串,但您可以将其包装在Arel.sql中以防止将来出现弃用问题:

Label.joins(:issues)
     .group(:name)
     .order(Arel.sql('count_id desc'))
     .count(:id)
     .take(10)

对此没有任何保证,所以如果您使用它,您应该在测试套件中包含一些内容,以便在将来行为发生变化时捕获任何问题。

© www.soinside.com 2019 - 2024. All rights reserved.