【问题标题】:Using Postgres, calculate count of association使用 Postgres,计算关联计数
【发布时间】:2013-02-01 07:42:15
【问题描述】:

我有 2 个模型

class Foo < ActiveRecord::Base
  # columns are
  # max_spots

  has_many :bars
end

class Bar < ActiveRecord::Base
  # columns are
  # a_id

  belongs_to :foo
end

我需要获取 max_spots 大于与其关联的条数的所有 Foos,但我需要通过活动记录而不是通过每个 Foos 来完成

class Foo
  #bad
  def self.bad_with_spots_left
    all.select do |foo|
      foo.max_spots - foo.bars.count > 0
    end 
  end

  #good but not working
  def self.good_with_spots_left
    joins(:bars).select('COUNT(bars.id) AS bars_count').where('max_spots - bars_count > 0')
  end
end

我知道我可以在 foo 中添加一个计数器缓存,但我只是想知道没有它我该怎么做。谢谢!

【问题讨论】:

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


    【解决方案1】:

    SQL 不允许在 WHERE 子句中使用别名,只能使用列名。

    作为替代方案,您可以尝试其中一种:

    在纯 SQL 中

    def self.good_with_spots_left
      where('foos.max_spots > (SELECT Count(*) FROM bars WHERE bars.a_id = foos.id)')
    end
    

    或者,用一点或红宝石(第二个select在红宝石中解释,因为它包含一个&块)

    def self.good_with_spots_left
      joins(:bars).select('foos.*', COUNT(bars.id) AS bars_count').group('bars.a_id').select{|foo| foo.max_spots > foo.bars_count}
    end
    

    【讨论】:

      【解决方案2】:

      当前接受的答案中的第一个解决方案效率低下,因为对foos 表中的每一行都执行了相关的子查询。对于这种情况,使用联接是一种更好的方法。

      当前接受的答案中的第二个解决方案不适用于没有任何 barsfoos

      例如:没有任何订单的新产品。

      您必须使用 LEFT 外连接来解决此问题。除此之外,计数比较可以使用having 子句来完成。这样整个操作都在数据库中处理。

      def self.good_with_spots_left
        joins("LEFT OUTER JOIN bars bars ON bars.foo_id = foos.id").
        group('bars.foo_id').
        having("foos.max_spots > COUNT(COALESCE(bars.foo_id, 0))")
      end
      

      注意:

      COALESCE 命令返回第一个非空输入。此命令与 SQL92 兼容,因此可以跨数据库运行。

      我们为什么使用COALESCE

      foo 没有匹配的bars 时,LEFT OUTER JOINbars.foo_id 返回NULL 值。 SQL COUNT 操作不喜欢集合中的NULL 值,因此我们将NULL 值转换为0

      【讨论】:

        猜你喜欢
        • 2013-10-10
        • 2021-10-28
        • 2016-10-15
        • 2021-03-23
        • 2020-05-28
        • 2010-10-06
        • 2022-08-23
        • 1970-01-01
        • 2021-11-17
        相关资源
        最近更新 更多