column - Obteniendo Mínimo/Máximo para cada grupo en ActiveRecord
sum active record (4)
Puede usar # find_by_sql
, pero esto implica devolver un objeto modelo, que podría no ser el que desea.
Si quiere ir al descubierto, también puede usar # 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 es solo una herramienta. Lo usas cuando es conveniente. Cuando SQL hace un mejor trabajo, lo usa.
Esta es una pregunta ancestral en la que se le da una tabla con los atributos ''tipo'', ''variedad'' y ''precio'', que usted obtiene el registro con el precio mínimo para cada tipo que hay.
En SQL, podemos hacer esto de la siguiente manera:
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;`
Quizás podríamos imitar esto por:
minprices = Table.minimum(:price, :group => type)
result = []
minprices.each_pair do |t, p|
result << Table.find(:first, :conditions => ["type = ? and price = ?", t, p])
end
¿Hay una mejor implementación que esta?
He estado luchando con esto por un tiempo y, por el momento, parece que estás bastante atrapado en la generación de SQL.
Sin embargo, tengo un par de mejoras para ofrecer.
En lugar de find_by_sql
, como sugirió @ François, he usado ActiveRecord''s to_sql
y me he to_sql
para "guiar" mi SQL un poco:
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>)
Como puede ver, sigo usando SQL sin procesar, pero al menos solo está en la parte donde AR no brinda soporte (AFAIK ActiveRecord simplemente no puede administrar INNER JOIN ... ON ...
) y no en todo .
El uso de joins
lugar de find_by_sql hace que la consulta se pueda encadenar: puede agregar condiciones adicionales, ordenar la tabla o poner todo en un ámbito.
Para actualizar la respuesta de Avdi arriba:
Table.minimum (: price,: group =>: type)
Aquí está la URL actualizada:
http://api.rubyonrails.org/classes/ActiveRecord/Calculations.html#method-i-minimum
Table.minimum(:price, :group => :type)
Consulte http://api.rubyonrails.org/classes/ActiveRecord/Calculations.html#method-i-minimum para obtener más información.