Fetching Minimum/Maximum for each group in ActiveRecord

我只是一个虾纸丫 提交于 2019-12-03 13:08:03

问题


This is an age-old question where given a table with attributes 'type', 'variety' and 'price', that you fetch the record with the minimum price for each type there is.

In SQL, we can do this by:

select f.type, f.variety, f.price   
from (  select type, min(price) as minprice from table group by type ) as x  
inner join table as f on f.type = x.type and f.price = x.minprice;`

We could perhaps imitate this by:

minprices = Table.minimum(:price, :group => type)  
result = []
minprices.each_pair do |t, p|  
   result << Table.find(:first, :conditions => ["type = ? and price = ?", t, p])
end

Is there a better implementation than this?


回答1:


Table.minimum(:price, :group => :type)

See http://api.rubyonrails.org/classes/ActiveRecord/Calculations.html#method-i-minimum for more.




回答2:


You can use #find_by_sql, but this implies returning a model object, which might not be what you want.

If you want to go bare to the metal, you can also use #select_values:

data = ActiveRecord::Base.connection.select_values("
        SELECT f.type, f.variety, f.price
        FROM (SELECT type, MIN(price) AS minprice FROM table GROUP BY type ) AS x
        INNER JOIN table AS f ON f.type = x.type AND f.price = x.minprice")
puts data.inspect
[["type", "variety", 0.00]]

ActiveRecord is just a tool. You use it when it's convenient. When SQL does a better job, you use that.




回答3:


I've been fighting with this for a while and for the moment it seems that you are pretty much stuck with generating SQL.

However, I have a couple refinements to offer.

Instead of find_by_sql, as @François suggested, I've used ActiveRecord's to_sql and joins to "guide" my SQL a little bit:

subquery_sql = Table.select(["MIN(price) as price", :type]).group(:type).to_sql
joins_sql    = "INNER JOIN (#{subquery_sql}) as S
                ON table.type = S.type
                AND table.price = S.price"

Table.joins(joins_sql).where(<other conditions>).order(<your order>)

As you can see, I'm still using raw SQL, but at least it's only on the part where AR gives no support (AFAIK ActiveRecord simply can't manage INNER JOIN ... ON ...) and not on the whole thing.

Using joins instead of find_by_sql makes the query chainable - you can add extra conditions, or sort the table, or put everything in a scope.




回答4:


To update Avdi's answer above:

Table.minimum(:price, :group => :type)

Here is the updated URL:

http://api.rubyonrails.org/classes/ActiveRecord/Calculations.html#method-i-minimum



来源:https://stackoverflow.com/questions/185569/fetching-minimum-maximum-for-each-group-in-activerecord

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!