不知道该如何命名标题,但是我很难将原始SQL重写为Rails ActiveRecord方法。
我想在选择的日期范围内按月提取交易总额。
注意:需要显示该范围内的所有月份。
为此,我使用了generate_series
SQL方法来生成该范围内的一系列月份。
我正在编写的方法在Query对象中,该对象具有一个已存在的关系,该关系已从之前筛选出事务。
我目前的功能:
def group_total_by_months
@relation.joins("RIGHT JOIN generate_series(TIMESTAMP '1-1-2018', TIMESTAMP '1-1-2020', interval '1 month') AS series
ON date_trunc('month', transactions.payment_date) = series")
.group("series")
.select("series AS payment_date, sum(transactions.total) AS total")
end
结果:
#<ActiveRecord::AssociationRelation [#<Transaction id: nil, total: 0.61173e3, payment_date: "2019-06-01 00:00:00">, #<Transaction id: nil, total: 0.364446e4, payment_date: "2019-10-01 00:00:00">, #<Transaction id: nil, total: 0.1625e4, payment_date: "2019-08-01 00:00:00">]>
这是按月总计的总和,但只有交易中存在的月份。为什么?因为生成的SQL看起来像这样,并且FROM子句来自所有事务,而不是来自筛选的事务:
SELECT series AS payment_date, sum(transactions.total) AS total FROM \"transactions\"
RIGHT JOIN generate_series(TIMESTAMP '1-1-2018', TIMESTAMP '1-1-2020', interval '1 month') AS series\n ON date_trunc('month', transactions.payment_date) = series
WHERE \"transactions\".\"account_id\" = 1
GROUP BY series
我需要如下所示的SQL :
WITH filteret_transactions AS (
SELECT * FROM transactions WHERE transactions.account_id = 1
)
SELECT series AS payment_date, sum(filteret_transactions.total) AS total
FROM filteret_transactions
RIGHT JOIN generate_series(TIMESTAMP '1-1-2018', TIMESTAMP '1-1-2020', interval '1 month') AS series
ON date_trunc('month', filteret_transactions.payment_date) = series GROUP BY series
我该如何实现?
答案 0 :(得分:1)
您需要在加入之前应用条件。您可以像第一种方法一样传递所需的参数作为参数并进行查询。我已经在联接本身中添加了条件(可以根据需要添加更多条件),并使用模型本身(事务)进行联接。
def group_total_by_months(account_id: )
Transaction.joins("RIGHT JOIN generate_series(TIMESTAMP '1-1-2018', TIMESTAMP '1-1-2020', interval '1 month') AS series
ON date_trunc('month', transactions.payment_date) = series AND transactions\".\"account_id\" = #{account_id}")
.group("series")
.select("series AS payment_date, sum(transactions.total) AS total")
end
编辑:可能的解决方案(但不适用于所有情况)
您可以使用此方法(https://apidock.com/rails/ActiveRecord/Relation/where_values_hash)获得适用的where条件。创建查询条件并在原始查询中使用它。
def group_total_by_months
applied_conditions = []
@transation.where_values_hash.each do |p|
applied_conditions << "AND #{p.first} = #{p.second}"
end
Transaction.joins("RIGHT JOIN generate_series(TIMESTAMP '1-1-2018', TIMESTAMP '1-1-2020', interval '1 month') AS series
ON date_trunc('month', transactions.payment_date) = series #{applied_conditions.join(' ')}")
.group("series")
.select("series AS payment_date, sum(transactions.total) AS total")
end
注意
>> Project.where(id: 12).where_values_hash
>> {"id"=>12}
>> Project.where('id = 12').where_values_hash
>> {}