19

我继承了以下数据库设计。表格是:

customers
---------
customerid  
customernumber

invoices
--------
invoiceid  
amount

invoicepayments
---------------
invoicepaymentid  
invoiceid  
paymentid

payments
--------
paymentid  
customerid  
amount

我的查询需要返回给定客户编号的 invoiceid、发票金额(在 invoices 表中)和应付金额(发票金额减去已向发票支付的任何款项)。一个客户可能有多个发票。

当对发票进行多次付款时,以下查询为我提供了重复记录:

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'

我该如何解决这个问题?

4

5 回答 5

18

我不确定我得到了你,但这可能是你正在寻找的:

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

如果每张发票有多个付款行,这将为您提供金额总和

于 2009-08-06T23:44:37.057 回答
9

非常感谢您的回复!

Saggi Malachi,不幸的是,如果有不止一次付款,该查询会计算发票金额。假设一张 39 美元的发票有两次付款,分别是 18 美元和 12 美元。因此,与其最终得到如下结果:

1   39.00   9.00

你最终会得到:

1   78.00   48.00

Charles Bretana,在将我的查询缩减为最简单的查询的过程中,我(愚蠢地)省略了一个额外的表 customerinvoices,它提供了客户和发票之间的链接。这可用于查看尚未付款的发票。

经过一番挣扎,我认为以下查询返回了我需要的内容:

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'

你们会同意吗?

于 2009-08-07T18:13:54.353 回答
4

对于那些想要从同一个表中获取各种聚合值的人,我有一个提示。

假设我有用户表和用户获得的积分表。所以他们之间的联系是1:N(一个用户,多点记录)。

现在,在“积分”表中,我还存储了有关用户获得积分的信息(登录、点击横幅等)。我想列出按SUM(points)AND 然后按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,具体取决于它是否等于我们想要的点的类型。

于 2010-06-22T15:54:40.503 回答
3

首先,Invoices 表中不应该有一个 CustomerId 吗?事实上,您无法对尚未付款的发票执行此查询。如果发票上没有付款,则该发票甚至不会显示在查询的输出中,即使它是外部连接...

另外,当客户付款时,您怎么知道要附在哪个发票上?如果唯一的方法是通过付款到达的存根上的 InvoiceId,那么您(可能不恰当地)将发票与付款的客户相关联,而不是与订购它们的客户相关联......。(有时发票可以由订购服务的客户以外的其他人支付)

于 2009-08-06T23:57:15.533 回答
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.
*/
于 2018-06-28T17:22:32.253 回答