来自具有匹配特定条件的关联模型的模型的Sum属性

时间:2017-01-09 23:20:34

标签: ruby-on-rails join activerecord sum has-many

在Ruby on Rails项目4.0中,我有Payments模型,has_many Transactions模型。

如果我有以下数据

SELECT * FROM payments;
id | paid_amount
---+--------------
1  | 200
2  | 300
3  | 100
4  | 400
5  | 100
6  | 600
7  | 100
8  | 100
9  | 800

SELECT * FROM transactions;
id | payment_id  | type
---+-------------+------
1  | 2           | cash
2  | 3           | credit
3  | 1           | credit
4  | 4           | cash
5  | 1           | cash
6  | 6           | credit
7  | 1           | cash
8  | 1           | credit
9  | 8           | cash

现在,我正在计算来自paid_amount的数字属性Payments的总和,该属性具有特定类型的交易,如下所示

> Payment.where(id: Transaction.where(type: 'cash').pluck(:payment_id)).sum(:paid_amount)
> 1000
> # The sum of paid_amount from payments with ids 1, 2, 4 and 8

但这对于成千上万的记录来说效率不够快,所以我试图用includes来完成这个,但没有任何运气。

> Payment.includes(:transactions).where("transactions.type = 'cash'").sum(:paid_amount)
> 1200
> # paid_amount of payment with id 1 is considered two times because of transactions with id 5 and 7

有关如何计算我需要的数字的任何想法?

2 个答案:

答案 0 :(得分:1)

您的第一个查询:

Payment.where(id: Transaction.where(type: 'cash').pluck(:payment_id)).sum(:paid_amount)

部分缓慢,部分原因是Transaction.where(type: 'cash').pluck(:payment_id)是一个返回数组的查询,然后您将该数组发送回SQL中的IN (big_list_of_integers)数据库。稍加修改将使用子查询,只需将pluck切换为select

Payment.where(id: Transaction.where(type: 'cash').select(:payment_id)).sum(:paid_amount)

将导致一个查询,如:

select sum(payments.paid_amount)
from payments
where payments.id in (
  select payment_id
  from transactions
  where transactions.type = ...
)

被发送到数据库。对于大型列表,这应该会快得多。

答案 1 :(得分:-1)

joinswhere一起使用,只返回您想要的交易

joins documentation

Payment.joins(:transactions).where(transactions: {type:'cash'}).sum(:paid_amount)