MySQL/Ruby on Rails — как СУММИТЬ в случае :has_many

У меня есть следующие таблицы:

Пользователь :has_many Purchases
Элемент :has_many Purchases

У товара есть столбец "сумма" (может быть + или -), и мне нужно найти всех пользователей, у которых есть положительная СУММА "Item.amounts" (по всем покупкам, которые сделал каждый).

Как выглядит этот запрос? (В данном случае я не уверен, как правильно обрабатывать «СУММ».)

Я начал со следующего, но, очевидно, это неправильно... (это не будет "включать" покупки, у которых есть предмет с отрицательным значением предмета...)

@users = User.find(:all,
:include => {:purchases => :item},
:select => "СУММА(item.amount)",
:order => " ...",
:conditions => "...",
:group => "users.id",
:having => "SUM(item.amount) > 0" )

Спасибо за помощь!
Том


person TomDogg    schedule 07.07.2010    source источник


Ответы (2)


Попробуй это:

User.all(:joins => items, :group => "users.id", 
          :having => "SUM(items.amount) > 0")
person Harish Shetty    schedule 07.07.2010
comment
Спасибо - это работает как нужно! 1 вопрос назад: как объяснить, что это работает с :joins, но не с :include? - person TomDogg; 08.07.2010
comment
В предложении :include используется LEFT OUTER JOIN, что приводит к нулевому количеству пользователей без элементов. Функция SUM не любит NULL. Кроме того, в данной ситуации больше подходит :joins, чем :include. - person Harish Shetty; 08.07.2010

Похоже, это хороший случай для некоторых модельных методов.

Я не проверял это, но я думаю, что вы хотите сделать что-то похожее на следующее:

class User < ActiveRecord::Base

has_many :purchases
has_many :items, :through => :purchases

def items_total
  #get all the items iterate over them to get the amount, 
  #compact to get rid of nils
  #and reduce with a sum function to total and return
  items.all.each{|item| item.amount}.compact.reduce(:+)
end

потом

User.items_total

person Jed Schneider    schedule 07.07.2010
comment
Спасибо, но, если я не ошибаюсь, похоже, есть недоразумение: ваше решение, кажется, возвращает сумму (мне действительно нужны пользователи для указанных условий). Кстати, я никогда не сталкивался с .reduce(:+) - есть идеи, где я могу найти документацию для этого? - person TomDogg; 08.07.2010
comment
да, вы правы, я думал, вы искали общее количество элементов для пользователя в контексте типа «общий итог». уменьшить(:+) является сокращением для сокращения{|сумма, я| sum+i}, который в основном суммирует все элементы в коллекции. apidock.com/ruby/Enumerable/reduce - person Jed Schneider; 08.07.2010