Как использовать несколько агрегатных функций одновременно в Rails / ActiveRecord? - PullRequest
8 голосов
/ 12 ноября 2011

Я хочу сделать несколько агрегатных функций одновременно, например, чтобы получить максимальный и минимальный идентификаторы, сгруппированные по статусу:

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

Это не работает (по крайней мере, с Rails 3.1.1) - вы получаете ошибку при минимальном вызове, говоря, что она не определена в Fixnum.

NoMethodError: undefined method `minimum' for 22377:Fixnum

Я мог бы сделать raw sql для него - но просто интересно, есть ли опция более высокого уровня / Rails ...

Спасибо, Крис

Ответы [ 3 ]

13 голосов
/ 12 ноября 2011

Я верю, что @topek прав, что вы не можете связать функции вычисления, подобные этой. Я думаю, вам придется использовать SQL в предикате select, например ::10000

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

Я только что проверил это в своем собственном проекте, и он, кажется, работает как ожидалось.

13 голосов
/ 30 октября 2014

У меня была похожая проблема, которую я решил с помощью группы с pluck в Rails 4. Например,

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

Также работает с наличием, порядком и т. Д. И с вычисляемыми столбцами.1006 * Приветствия

4 голосов
/ 12 ноября 2011

Я не думаю, что это возможно с этими агрегатными функциями, потому что они возвращают значение, а не область, см. документы . Все они используют метод вычисления, который, как вы видите, возвращает число:

     # 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...