1

我有一张invoices桌子。每张发票都有许多invoice_itemstransactions(或者,如果您愿意,“付款”)。对于每张发票,我想计算已付金额(即其交易金额的总和)和总金额(即项目金额的总和)。

我写了以下查询:

SELECT 
  invoices.*,
  SUM(transactions.amount_cents) AS amount_paid,
  SUM(invoice_items.quantity * invoice_items.price_cents) AS total
FROM invoices
RIGHT JOIN transactions 
  ON invoices.id = transactions.invoice_id
RIGHT JOIN invoice_items 
  ON invoices.id = invoice_items.invoice_id

但是,total出于某种原因,该字段的值乘以交易次数(例如,如果我有一张总金额为20的发票和2笔交易,则该total字段为40)。

如果我从查询中删除对事务的所有引用:

SELECT 
  invoices.*,
  SUM(invoice_items.quantity * invoice_items.price_cents) AS total
FROM invoices
RIGHT JOIN invoice_items 
  ON invoices.id = invoice_items.invoice_id

total字段正确返回...

我不是这方面的专家,所以我可能正在做一些非常愚蠢的事情。我已经尝试过不同的 JOIN 组合,但没有结果。

有什么提示吗?

编辑:半最终解决方案

我试图得到未付的发票,所以这是最后的查询:

SELECT 
  invoices.*,
  SUM(invoice_items.quantity * invoice_items.price_cents) AS total,
t.amount_paid
FROM invoices
LEFT JOIN invoice_items 
  ON invoice_items.invoice_id = invoices.id
LEFT JOIN (
  SELECT 
    invoice_id, 
    SUM(transactions.amount_cents) AS amount_paid
  FROM transactions 
  GROUP BY invoice_id
) t
  ON invoices.id = t.invoice_id
GROUP BY invoices.id
HAVING amount_paid >= total;

编辑:意识到我不需要加入之后...

我真的不需要获取相关数据。我只想知道发票是已付还是未付。所以我最终使用了一个简单的 where:

SELECT `invoices`.* 
FROM `invoices` 
WHERE (
  (
    SELECT COALESCE(SUM(t.amount_cents), 0)
    FROM transactions t 
    WHERE t.invoice_id = invoices.id
  )
  >=
  (
    SELECT COALESCE(SUM(i.quantity * i.price_cents), 0)
    FROM invoice_items i
    WHERE i.invoice_id = invoices.id
  )
)

但是感谢所有帮助过的人。

4

2 回答 2

2

您可以使用子查询将事务聚合到每个 invoice_id 最多一行,这样就不会导致出现额外的行。根据卷,您可能希望将子查询放入临时表并引用临时表。

SELECT 
  invoices.*,
  SUM(invoice_items.quantity * invoice_items.price_cents) AS total,
t.Amount_Paid
FROM invoices
LEFT JOIN invoice_items 
  ON invoice_items.invoice_id = invoices.id
LEFT JOIN (select invoice_id, SUM(transactions.amount_cents) as Amount_Paid from
transactions group by invoice_id) t
  ON invoices.id = t.invoice_id
GROUP BY invoices.id
于 2013-06-10T13:54:02.107 回答
2

您的重复是基于笛卡尔结果...正如您所指出的,一张发票有多个交易,因此每次交易金额都会被计算在内。您可能需要各个表中的子查询才能按发票 ID 自行分组获得总计...

SELECT 
      invoices.*,
      Payments.Amount_Paid,
      Items.Items_Total
   FROM 
      invoices
         JOIN ( select
                      T.Invoice_ID, 
                      sum( T.amount_cents ) amount_paid
                   from 
                      transactions T
                   group by
                      T.Invoice_ID ) Payments
            on Invoices.id = Payments.Invoice_ID
         JOIN ( select
                      II.Invoice_ID, 
                      sum( II.quantity * II.price_cents) AS Items_total
                   from 
                      Invoice_Items II
                   group by
                      II.Invoice_ID ) Items
            on Invoices.id = Items.Invoice_ID
于 2013-06-10T13:58:52.143 回答