如何在Rails / ActiveRecord中一次使用多个聚合函数?

时间:2011-11-11 21:28:16

标签: ruby-on-rails ruby activerecord

我想一次做几个聚合函数,例如,按状态分组最大和最小ID:

Model.maximum(:id).minimum(:id).group(:status)

这不起作用(至少使用Rails 3.1.1) - 你在最小调用上得到一个错误,说它没有在Fixnum上定义。

NoMethodError: undefined method `minimum' for 22377:Fixnum

我可以为它做原始的SQL - 但只是想知道是否有更高级别的/ Rails选项......

谢谢,克里斯

3 个答案:

答案 0 :(得分:13)

我相信@topek是对的,你不能像这样链接计算功能。我认为你必须在select谓词中使用SQL,例如:

Model.select('MAX(id) AS `maximum`, MIN(id) AS `minimum`').group(:status)

我刚刚在我自己的项目中对此进行了测试,它似乎按预期工作。

答案 1 :(得分:13)

我有一个类似的问题,我在使用Rails 4中的组中解决了这个问题。例如

Model.group(:status).pluck('min(id)','max(id)')

也适用于拥有,订购等和计算列。

Model.group('CAST(created_at AS Date), EXTRACT(HOUR FROM created_at), floor(EXTRACT(MINUTE FROM created_at)/15) * 15')
     .having('count(id) > 10')
     .order('min(created_at)')
     .pluck('count(id)')

干杯

答案 2 :(得分:4)

我不认为这些聚合函数可以实现这一点,因为它们返回的是值,而不是范围,请参阅docs。它们都使用calculate方法,如您所见,返回一个数字:

     # File lib/active_record/calculations.rb, line 117
117:       def calculate(operation, column_name, options = {})
118:         validate_calculation_options(operation, options)
119:         column_name     = options[:select] if options[:select]
120:         column_name     = '*' if column_name == :all
121:         column          = column_for column_name
122:         catch :invalid_query do
123:           if options[:group]
124:             return execute_grouped_calculation(operation, column_name, column, options)
125:           else
126:             return execute_simple_calculation(operation, column_name, column, options)
127:           end
128:         end
129:         0
130:       end

如果你想这样做,你必须手工制作查询。

以下是一个例子:

sql = "SELECT max(id) as max_id,
              min(id) as min_id
         FROM model
       GROUP
           BY status
    "
Model.find_by_sql(sql).each do |row|
  puts "min. id: #{row.min_id}, " << 
       "max. id: #{row.max_id}, "
end