在我的Rails应用程序中,我具有以下模型:
class Person < ApplicationRecord
has_many :payments
end
class Payment < ApplicationRecord
belongs_to :person
end
如何获得每个payments
的{{1}}并按 sum 排序?
这是我的控制者:
person
它给我正确的数字,但顺序错误。我希望它从class SalesController < ApplicationController
def index
@people = current_account.people.includes(:payments).where(:payments => { :date => @range }).order("payments.amount DESC")
end
end
内付款金额最高的person
开始。
这是当前的range
表:
这怎么办?
答案 0 :(得分:2)
这应该为您工作:
payments = Payment.arel_table
sum_payments = Arel::Table.new('sum_payments')
payments_total = payments.join(
payments.project(
payments[:person_id],
payments[:amount].sum.as('total')
)
.where(payments[:date].between(@range))
.group( payments[:person_id])
.as('sum_payments'))
.on(sum_payments[:person_id].eq(Person.arel_table[:id]))
这将创建损坏的SQL(从语法上不正确的付款中选择任何内容,并连接到此查询中甚至不存在的人),但实际上我们只需要连接,例如
payments_total.join_sources.first.to_sql
#=> INNER JOIN (SELECT payments.person_id,
# SUM(payments.amount) AS total
# FROM payments
# WHERE
# payments.date BETWEEN ... AND ...
# GROUP BY payments.person_id) sum_payments
# ON sum_payments.id = people.id
因此知道了这一点,我们就可以将join_sources
传递给ActiveRecord::QueryMethods#joins
并让rails
和arel
像这样处理其余部分
current_account
.people
.includes(:payments)
.joins(payments_total.join_sources)
.where(:payments => { :date => @range })
.order("sum_payments.total DESC")
哪个应导致SQL类似于
SELECT
-- ...
FROM
people
INNER JOIN payments ON payments.person_id = people.id
INNER JOIN ( SELECT payments.person_id,
SUM(payments.amount) as total
FROM payments
WHERE
payments.date BETWEEN -- ... AND ...
GROUP BY payments.person_id) sum_payments ON
sum_payments.person_id = people.id
WHERE
payments.date BETWEEN -- ... AND ..
ORDER BY
sum_payments.total DESC
这将显示所有在给定日期范围内付款的人(以及这些付款),并按这些付款的总和降序排列。
这是未经测试的,因为我不必费心设置整个Rails应用程序,但它应该可以工作。