如何获得按列分组的加权平均值

时间:2016-05-30 23:12:27

标签: ruby-on-rails postgresql

我的模型 var hideLogin = true ; $('#ModalHelpLogin').on('shown.bs.modal', function (e) { hideLogin = false ; }) $('#ModalHelpLogin').on('hidden.bs.modal', function (e) { hideLogin = true ; }) $('#DropLogin').on('hide.bs.dropdown', function () { return hideLogin ; }); 包含Companypbrmarket_cap列。

要获得按category分组的pbr的平均值,我可以使用category方法。

group

但是没有加权平均法。

要获得加权平均值,我需要运行此SQL代码。

Company.group(:category).average(:pbr)

select case when sum(market_cap) = 0 then 0 else sum(pbr * market_cap) / sum(market_cap) end as weighted_average_pbr, category AS category FROM "companies" GROUP BY "companies"."category"; 中,此查询可以正常运行。但我不知道如何使用Rails。

psql

返回错误:

sql = %q(select case when sum(market_cap) = 0 then 0 else sum(pbr * market_cap) / sum(market_cap) end as weighted_average_pbr, category AS category FROM "companies" GROUP BY "companies"."category";)
ActiveRecord::Base.connection.select_all(sql)

最好是我可以扩展Rails方法,以便我可以使用

 output error: #<NoMethodError: undefined method `keys' for #<Array:0x007ff441efa618>>

但我听说扩展rails查询有点蠢,现在我只想知道如何从Rails运行sql的结果。

有谁知道怎么做?

版本

rails:4.2.1

1 个答案:

答案 0 :(得分:1)

您使用的是什么版本的Rails?我没有得到Rails 4.2的错误。在Rails 3.2中select_all用于返回Arrayin 4.2,它返回ActiveRecord::Result。但在任何一种情况下,没有keys方法是正确的。相反,您需要在keysArray的每个元素上调用Result。听起来问题不是来自运行查询,而是来自你之后正在做的事情。

在任何情况下,为了获得您所描述的更流畅的方法,您可以这样做:

class Company
  scope :weighted_average, lambda{|col|
    select("companies.category").
    select(<<-EOQ)
      (CASE WHEN SUM(market_cap) = 0 THEN 0
            ELSE SUM(#{col} * market_cap) / SUM(market_cap)
       END) AS weighted_average_#{col}
    EOQ
  }

这将让您说Company.group(:category).weighted_average(:pbr),您将获得Company个实例的集合。每个人都有一个额外的weighted_average_pbr属性,所以你可以这样做:

Company.group(:category).weighted_average(:pbr).each do |c|
  puts c.weighted_average_pbr
end

这些实例具有正常属性,但它们将具有category。这是因为它们不代表单个公司,而是代表具有相同category的公司组。如果要按其他方式分组,可以参数化lambda以获取分组列。在这种情况下,您也可以将group调用移动到lambda中。

现在被警告weighted_average的参数直接进入您的SQL查询而不转义,因为它是一个列名。因此,请确保您没有将用户输入传递给该方法,否则您将遇到SQL注入漏洞。事实上,我可能会在lambda中放一个警卫,比如raise "NOPE" unless col =~ %r{\A[a-zA-Z0-9_]+\Z}

更一般的教训是,您可以使用select包含额外的SQL表达式,并让Rails神奇地将它们视为从查询返回的实例上的属性。

另请注意,与select_all不同的是,您获得了大量哈希值,使用此方法可以获得大量Company个实例。所以再没有keys方法! : - )