2011-11-11 14 views
7

Quiero hacer varias funciones agregadas a la vez, por ejemplo, para obtener la década de máximo y mínimo id agrupados por estado:¿Cómo usar varias funciones agregadas a la vez en Rails/ActiveRecord?

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

Esto no funciona (al menos con rieles 3.1.1) - se produce un error en la llamada mínima, diciendo que no está definida en Fixnum.

NoMethodError: undefined method `minimum' for 22377:Fixnum 

que podía hacer sql prima para ella - pero sólo me preguntaba si hay una opción de alto nivel/rieles ...

Gracias, Chris

Respuesta

13

Creo @topek es correcto que no puede encadenar las funciones de cálculo de este tipo. Creo que tendrá que utilizar SQL en un predicado select, por ejemplo .:

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

acabo probado esto en un proyecto de mi propia y parece funcionar como se espera.

+1

Eso se ve mejor para mí, agradable. –

3

No creo que esto es posible con estas funciones agregadas, porque devuelven un valor y no un ámbito, consulte docs. Todos ellos utilizan el método de cálculo, que como se puede ver devuelve un número:

 # 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 

Si quieres hacer esto, usted tiene que diseñar la consulta con la mano.

Aquí se muestra un ejemplo:

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 
+0

Ok- se ve bien, gracias por eso. –

12

Tuve un problema similar que resolví utilizando el grupo con pluck en Rails 4. Por ejemplo,

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

También funciona con have, order etc y con columnas calculadas.

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)') 

Saludos

+0

Gracias, esto funciona genial. – jayant

Cuestiones relacionadas