我继承了以下数据库设计。表格是:
customers
---------
customerid
customernumber
invoices
--------
invoiceid
amount
invoicepayments
---------------
invoicepaymentid
invoiceid
paymentid
payments
--------
paymentid
customerid
amount
我的查询需要返回给定客户编号的invoiceid,发票金额(在发票表中)和应付金额(发票金额减去对发票的任何付款)。客户可能有多张发票。
以下查询在向发票进行多次付款时向我提供了重复记录:
SELECT i.invoiceid, i.amount, i.amount - p.amount AS amountdue
FROM invoices i
LEFT JOIN invoicepayments ip ON i.invoiceid = ip.invoiceid
LEFT JOIN payments p ON ip.paymentid = p.paymentid
LEFT JOIN customers c ON p.customerid = c.customerid
WHERE c.customernumber = '100'
我该如何解决这个问题?
答案 0 :(得分:13)
我不确定我能不能找到你,但这可能就是你想要的:
SELECT i.invoiceid, sum(case when i.amount is not null then i.amount else 0 end), sum(case when i.amount is not null then i.amount else 0 end) - sum(case when p.amount is not null then p.amount else 0 end) AS amountdue
FROM invoices i
LEFT JOIN invoicepayments ip ON i.invoiceid = ip.invoiceid
LEFT JOIN payments p ON ip.paymentid = p.paymentid
LEFT JOIN customers c ON p.customerid = c.customerid
WHERE c.customernumber = '100'
GROUP BY i.invoiceid
如果每张发票有多个付款行,这将为您提供金额总和
答案 1 :(得分:6)
非常感谢您的回复!
Saggi Malachi,不幸的是,该查询会在有多笔付款的情况下汇总发票金额。假设有一笔价值18美元和12美元的39美元发票有两笔付款。因此,而不是结果看起来像:
1 39.00 9.00
你最终会得到:
1 78.00 48.00
Charles Bretana,在我的查询到最简单的查询的过程中,我(愚蠢地)省略了另一个表customerIvoices,它提供了客户和发票之间的链接。这可用于查看尚未付款的发票。
经过多次努力之后,我认为以下查询会返回我需要的内容:
SELECT DISTINCT i.invoiceid, i.amount, ISNULL(i.amount - p.amount, i.amount) AS amountdue
FROM invoices i
LEFT JOIN invoicepayments ip ON i.invoiceid = ip.invoiceid
LEFT JOIN customerinvoices ci ON i.invoiceid = ci.invoiceid
LEFT JOIN (
SELECT invoiceid, SUM(p.amount) amount
FROM invoicepayments ip
LEFT JOIN payments p ON ip.paymentid = p.paymentid
GROUP BY ip.invoiceid
) p
ON p.invoiceid = ip.invoiceid
LEFT JOIN payments p2 ON ip.paymentid = p2.paymentid
LEFT JOIN customers c ON ci.customerid = c.customerid
WHERE c.customernumber='100'
你们会同意吗?
答案 2 :(得分:2)
首先,发票表中是否应该有CustomerId?实际上,您无法对尚未付款的发票执行此查询。如果发票上没有付款,则该发票甚至不会显示在查询的输出中,即使它是外部联接......
此外,当客户付款时,您如何知道要将其附加到哪个发票?如果唯一的方法是通过支付到达的存根上的InvoiceId,那么您(可能不恰当地)将发票与支付它们的客户相关联,而不是与订购它们的客户相关联...... (有时发票可以由订购服务的客户以外的其他人支付)
答案 3 :(得分:2)
对于那些希望从同一个表中获取各种聚合值的人,我有一个提示。
假设我有用户和表格的表格,用户可以获得积分。因此它们之间的连接是1:N(一个用户,多个点记录)。
现在在表'points'中我还存储了有关用户获得积分的信息(登录,点击横幅等)。我想列出按SUM(points)
订购的所有用户,然后按SUM(points WHERE type = x)
列出。也就是说,按用户拥有的所有点排序,然后按用户获得的点数进行特定操作(例如登录)。
SQL将是:
SELECT SUM(points.points) AS points_all, SUM(points.points * (points.type = 7)) AS points_login
FROM user
LEFT JOIN points ON user.id = points.user_id
GROUP BY user.id
这是美丽的SUM(points.points * (points.type = 7))
,其中内括号的计算结果为0或1,因此将给定的点值乘以0或1,这取决于它是否等于我们想要的点的类型。
答案 4 :(得分:0)
我知道这很晚了,但确实可以回答您的原始问题。
/*Read the comments the same way that SQL runs the query
1) FROM
2) GROUP
3) SELECT
4) My final notes at the bottom
*/
SELECT
list.invoiceid
, cust.customernumber
, MAX(list.inv_amount) AS invoice_amount/* we select the max because it will be the same for each payment to that invoice (presumably invoice amounts do not vary based on payment) */
, MAX(list.inv_amount) - SUM(list.pay_amount) AS [amount_due]
FROM
Customers AS cust
INNER JOIN
Payments AS pay
ON
pay.customerid = cust.customerid
INNER JOIN ( /* generate a list of payment_ids, their amounts, and the totals of the invoices they billed to*/
SELECT
inpay.paymentid AS paymentid
, inv.invoiceid AS invoiceid
, inv.amount AS inv_amount
, pay.amount AS pay_amount
FROM
InvoicePayments AS inpay
INNER JOIN
Invoices AS inv
ON inv.invoiceid = inpay.invoiceid
INNER JOIN
Payments AS pay
ON pay.paymentid = inpay.paymentid
) AS list
ON
list.paymentid = pay.paymentid
/* so at this point my result set would look like:
-- All my customers (crossed by) every paymentid they are associated to (I'll call this A)
-- Every invoice payment and its association to: its own ammount, the total invoice ammount, its own paymentid (what I call list)
-- Filter out all records in A that do not have a paymentid matching in (list)
-- we filter the result because there may be payments that did not go towards invoices!
*/
GROUP BY
/* we want a record line for each customer and invoice ( or basically each invoice but i believe this makes more sense logically */
cust.customernumber
, list.invoiceid
/*
-- we can improve this query by only hitting the Payments table once by moving it inside of our list subquery,
-- but this is what made sense to me when I was planning.
-- Hopefully it makes it clearer how the thought process works to leave it in there
-- as several people have already pointed out, the data structure of the DB prevents us from looking at customers with invoices that have no payments towards them.
*/