来自具有匹配特定条件的关联模型的模型的总和属性
Sum attribute from model that has associated models that match certain condition
在 Rails 项目的 Ruby 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
现在,我正在计算来自 Payments
的数字属性 paid_amount
的总和,该属性具有特定类型的交易,如下所示
> 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
关于我应该如何计算我需要的数量有什么想法吗?
使用 joins
和 where
到 return 仅您想要的交易
Payment.joins(:transactions).where(transactions: {type:'cash'}).sum(:paid_amount)
您的第一个查询:
Payment.where(id: Transaction.where(type: 'cash').pluck(:payment_id)).sum(:paid_amount)
很慢,部分原因是 Transaction.where(type: 'cash').pluck(:payment_id)
是一个查询 returns 一个数组,然后您将该数组发送回数据库,并在 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 = ...
)
正在发送到数据库。对于大型列表,这应该会快很多。
在 Rails 项目的 Ruby 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
现在,我正在计算来自 Payments
的数字属性 paid_amount
的总和,该属性具有特定类型的交易,如下所示
> 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
关于我应该如何计算我需要的数量有什么想法吗?
使用 joins
和 where
到 return 仅您想要的交易
Payment.joins(:transactions).where(transactions: {type:'cash'}).sum(:paid_amount)
您的第一个查询:
Payment.where(id: Transaction.where(type: 'cash').pluck(:payment_id)).sum(:paid_amount)
很慢,部分原因是 Transaction.where(type: 'cash').pluck(:payment_id)
是一个查询 returns 一个数组,然后您将该数组发送回数据库,并在 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 = ...
)
正在发送到数据库。对于大型列表,这应该会快很多。