2014-12-13 2 views
1

Как добавить сумму поля из объединенной модели с использованием Rails 3.2 и MySql 5.5?Как добавить сумму поля из объединенной модели в Rails?

Скажем, у меня есть модели, как это:

class Account < ActiveRecord::Base 
    attr_accessible :number 
    has_many :operations 
end 

class Operation < ActiveRecord::Base 
    belongs_to :account 
    attr_accessible :op_type, # either 'deposit' or 'withdrawal' 
        :amount 
end 

нужно выбрать учетные записи с помощью некоторого условия и добавить к каждому из них суммы всех вкладов на счет.

Это можно сделать с помощью SQL, как это:

SELECT *, 
    IFNULL((
     SELECT SUM(amount) 
     FROM operations 
     WHERE operations.account_id = accounts.id AND operations.op_type = 'deposit' 
    ), 0) as total_deposits 
FROM accounts 
WHERE <condition for accounts> 

Как я могу сделать это с помощью Rails (с помощью LEFT JOIN другой способ достичь того же результата.)?

Я хочу что-то вроде этого:

accounts = Account.where(<mycondition>). join(???). sum(???) # What should be here? 
accounts.each do |a| 
    puts "Account #{a.number} has deposited #{a.total_deposits} total." 
end 

ответ

0

Try Operation.joins(:account).where(<mycondition>).sum(:amount)

поле подводятся amount в operations таблице; поэтому активный запрос записи будет также на модели Operation. mycondition должен быть определен для включения операций, принадлежащих конкретной учетной записи.

+0

'Operation.joins (: account)' не работает, потому что он не возвращает учетные записи, у которых еще нет учетных записей. Мне нужны эти учетные записи в наборе результатов. total_deposits должно быть 0 для них. –

0

Если вам нужно сделать LEFT JOIN для получения счета, даже если у них нет записи операции, вам нужно ввести, что условие соединения с чем-то вроде:

totals = Account.where(<account conditions>).joins("LEFT JOIN operations ON operations.account_id = accounts.id AND operations.op_type = 'deposit'").group("accounts.number").sum(:amount) 
totals.each do |a| 
    puts "Account #{a[0]} has deposited #{a[1]} total." 
end 

И если вы готовы разделить это на два запрос, это вариант:

accounts = Account.where(<account conditions>) 
totals = Operation.where(op_type: "deposit", account_id: accounts.map(&:id)).group(:account_id).sum(:amount) 
accounts.each do |a| 
    puts "Account #{a.number} has deposited #{totals[a.id] || 0} total." 
end 

Edit:. Если вам нужны экземпляры учетных записей и нужно отсортировать по суммам, некоторые дополнительный SQL начнет закрадываться Но что-то вроде этого должно работать:

accounts = Account.where(<account conditions>).joins("LEFT JOIN operations ON operations.account_id = accounts.id AND operations.op_type = 'deposit'").group("accounts.number").select("accounts.*, COALESCE(SUM(amount), 0) AS acct_total").order("acct_total") 
accounts.each do |a| 
    puts "Account #{a.number} has deposited #{a.acct_total} total." 
end 
+0

Первое решение создает SQL-запрос, который мне нужен, но его строки возвращаются в виде массивов в Ruby. Возможно ли получить экземпляры экземпляра? –

+0

Второе решение не соответствует моим потребностям, потому что мне нужно отсортировать набор результатов с помощью 'total_deposits desc'. (Для простоты я опустил сортировку в исходном вопросе). –

Смежные вопросы