假设我有一个连接到Payment
表的User
表。我想找到用户所有付款的总和,即使他们没有付款。我可能会做一些类似的事情:
User.left_joins(:payments).group(:id).pluck(:id, "SUM(amount)")
这将为没有付款记录的用户返回零值。然而,如果我应用任何类型的过滤,那个方面都会丢失。例如:
User.left_joins(:payments).where("payment_date > '2021-01-01'").group(:id).pluck(:id, "SUM(amount)")
输出将只包含在2021-01-01之后付款的用户。不会提及只在2021年之前付款或从未付款的用户。是否有一种方法可以将此信息保持为零或0,类似于第一个查询中的做法?
您是正确的,OUTER JOIN上的显式条件会创建INNER JOIN。为了按照要求执行,您需要一个复杂的连接条件,如
join_condition = Arel::Nodes::OuterJoin.new(
Payment.arel_table,
Arel::Nodes::On.new(
Payment.arel_attribute(:user_id).eq(User.arel_attribute(:id))
.and(Payment.arel_attribute(:payment_date).gt('2021-01-01'))
)
)
User.joins(join_condition).group(:id).pluck(:id, "SUM(amount)")
这将导致类似的结果
SELECT
users.id,
SUM(amount) as exp1
FROM
users
LEFT OUTER JOIN payments ON payments.user_id = users.id
AND payments.payment_date > '2021-01-01'
GROUP BY
users.id