2011-11-11 12 views
7

voglio fare diverse funzioni di aggregazione in una sola volta, ad esempio, per ottenere i massimi e minimo id raggruppati per stato:Come utilizzare più funzioni di aggregazione contemporaneamente in Rails/ActiveRecord?

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

Questo non funziona (almeno con Rails 3.1.1) - si ottiene un errore chiamata minima, dicendo che non è definita su Fixnum.

NoMethodError: undefined method `minimum' for 22377:Fixnum 

ho potuto fare prima per SQL - ma chiedo solo se v'è un'opzione di livello superiore/Rails ...

Grazie, Chris

risposta

13

Credo @topek è giusto che non si può a catena le funzioni di calcolo come questo. Penso che si dovrà utilizzare SQL in un select predicato, ad es .:

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

Ho appena testato questo in un progetto tutto mio e sembra funzionare come previsto.

+1

Questo mi sembra migliore - bello. –

3

Non credo che questo è possibile con queste funzioni aggregate, poiché restituiscono un valore e non un ambito, vedere docs. Tutti usano il metodo calcolo, che come si può vedere restituisce un numero:

 # 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 

Se si vuole fare questo, è necessario alle imbarcazioni la query a mano.

Ecco un esempio:

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- sembra buono, grazie per questo. –

12

Ho avuto un problema simile che ho risolto utilizzando il gruppo con cogliere in Rails 4. E.g.

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

Funziona anche con avere, ordinare ecc. E con colonne calcolate.

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

Acclamazioni

+0

Grazie, funziona benissimo. – jayant

Problemi correlati