【发布时间】:2017-10-24 20:57:15
【问题描述】:
假设我在 Rails 应用中有 3 个表:
发票
id | customer_id | employee_id | notes
---------------------------------------------------------------
1 | 1 | 5 | An order with 2 items.
2 | 12 | 5 | An order with 1 item.
3 | 17 | 12 | An empty order.
4 | 17 | 12 | A brand new order.
invoice_items
id | invoice_id | price | name
---------------------------------------------------------
1 | 1 | 5.35 | widget
2 | 1 | 7.25 | thingy
3 | 2 | 1.25 | smaller thingy
4 | 2 | 1.25 | another smaller thingy
invoice_payments
id | invoice_id | amount | method | notes
---------------------------------------------------------
1 | 1 | 4.85 | credit card | Not enough
2 | 1 | 1.25 | credit card | Still not enough
3 | 2 | 1.25 | check | Paid in full
这代表 4 个订单:
第一个有 2 个项目,总共 12.60。它有两次付款,总支付金额为 6.10。此订单已部分支付。
第二个只有一件物品,一件付款,合计1.25。此订单已全额付款。
第三个订单没有商品或付款。这对我们很重要,有时我们会使用这种情况。它也被视为全额支付。
最终订单又多了一件,总共 1.25,但目前还没有付款。
现在我需要一个查询:
显示所有尚未全额付款的订单;也就是说,所有订单的项目总和大于付款的总和。
我可以用纯 sql 来做:
SELECT invoices.*,
invoice_payment_amounts.amount_paid AS amount_paid,
invoice_item_amounts.total_amount AS total_amount
FROM invoices
LEFT JOIN (
SELECT invoices.id AS invoice_id,
COALESCE(SUM(invoice_payments.amount), 0) AS amount_paid
FROM invoices
LEFT JOIN invoice_payments
ON invoices.id = invoice_payments.invoice_id
GROUP BY invoices.id
) AS invoice_payment_amounts
ON invoices.id = invoice_payment_amounts.invoice_id
LEFT JOIN (
SELECT invoices.id AS invoice_id,
COALESCE(SUM(invoice_items.item_price), 0) AS total_amount
FROM invoices
LEFT JOIN invoice_items
ON invoices.id = invoice_items.invoice_id
GROUP BY invoices.id
) AS invoice_item_amounts
ON invoices.id = invoice_item_amounts.invoice_id
WHERE amount_paid < total_amount
但是...现在我需要将其放入 Rails(可能作为范围)。我可以使用 find_by_sql,但它会返回一个数组,而不是 ActiveRecord::Relation,这不是我需要的,因为我想将它与其他范围链接(例如,一个过期的范围,它使用这个)等。
所以原始 SQL 可能不是正确的方法......但是什么是?我无法使用 activerecord 的查询语言执行此操作。
到目前为止,我得到的最接近的是:
Invoice.select('invoices.*, SUM(invoice_items.price) AS total, SUM(invoice_payments.amount) AS amount_paid').
joins(:invoice_payments, :invoice_items).
group('invoices.id').
where('amount_paid < total')
但这失败了,因为对于像 #1 这样的订单,有多次付款,它错误地将订单价格翻了一番(由于多次加入),显示为仍未付款。我在 SQL 中遇到了同样的问题,这就是我按照我的方式构建它的原因。
这里有什么想法吗?
【问题讨论】:
-
您是否考虑在
invoices表中添加一些额外的列?也许您可以添加payment_total和total列,这将使这些查询变得轻而易举
标签: sql ruby-on-rails ruby-on-rails-4