【问题标题】:How to Sum previos rows summatory to find a balance in SQL Server如何总结以前的行总结以在 SQL Server 中找到平衡
【发布时间】:2019-01-18 20:57:21
【问题描述】:

我正在开发一项服务,该服务需要根据总发票金额和客户已支付的部分付款来计算客户欠款。

所以,在表格 A 中有一行包含发票总价值:

[dbo].[表A]

ID    CustomerId    InvoiceVal    
1     12            1000           
2     11            2000   
3     10            5000   
4     14            15000   
5     12            100   
6     16            8000   
7     18            3200

在表 B 中,我记录了每个客户对每张发票的部分付款:

[dbo].[TableB]

ID    InvoiceId    Payment
1     1            150   
2     3            50
3     1            120
4     1            100
5     5            90
6     4            7500

因此,如您所见,客户 12 有一张 1000 美元的发票,并支付了 3 次总金额为 370 美元的付款

我需要能够查看每一行的部分欠款,这是预期的结果:

No.    InoviceId    CustomerId    Payment    Owed
1      1            12            150        850
2      1            12            120        730
3      1            12            100        630

到目前为止,这是我的代码:

DECLARE @invid int = '1'

DECLARE @invoicetotal numeric(18,2)

SET @invoicetotal =
    (
        SELECT
            [dbo].[TableA].[InvoiceVal]
        FROM [dbo].[TableA]
        WHERE
            ([dbo].[TableA].[ID] = @invid)
    )

SELECT
    *,
    SUM(@invoicetotal - [dbo].[TableB].[Payment]) OVER(ORDER BY [dbo].[TableB].[ID] ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS [Owed]
FROM [dbo].[TableB]
WHERE
    ([dbo].[TableB].[InvoiceId] = @invid) 

但这就是我得到的:

ID    InvoiceId    Payment    Owed
1     1            150.00     NULL
3     1            120.00     850.00
4     1            100.00     1730.00

我需要在每一行总结之前的付款。

谢谢!

【问题讨论】:

  • 什么版本的 SQL Server?

标签: sql sql-server select


【解决方案1】:

这样的事情会有所帮助

SELECT 
  ROW_NUMBER() OVER (ORDER BY TableB.ID ASC) NO,
  CustomerId,
  Payment,
  InvoiceVal - SUM(Payment) OVER (PARTITION BY TableA.ID ORDER BY TableB.Id ASC) Owed
FROM TableA
INNER JOIN TableB
  ON TableA.Id = TableB.InvoiceId
WHERE 
  CustomerId = 12

Working Fiddle

【讨论】:

    【解决方案2】:

    您的查询将取决于您要作为最终输出的内容。

    如果你只想要 一个 CustomerID,请选择:

    SELECT a.ID AS InvoiceID, a.CustomerID, a.InvoiceVal AS StartInvoice
      , b.ID AS bid, b.Payment
      , a.InvoiceVal - ISNULL(SUM(b.Payment) OVER (PARTITION BY a.ID ORDER BY b.id),0) AS owed
    FROM TableA a 
    LEFT OUTER JOIN TableB b ON a.ID = b.InvoiceID
    WHERE a.CustomerID = 12
    

    如果 CustomerID 没有任何付款,您想使用 LEFT JOIN,这样您就不会消除欠款。

    SELECT a.ID AS aid, a.CustomerID,  a.InvoiceVal AS StartInvoice
      , b.ID AS bid, b.Payment
      , a.InvoiceVal - ISNULL(SUM(b.Payment) OVER (PARTITION BY a.ID ORDER BY b.id),0) AS owed
    FROM TableA a 
    LEFT OUTER JOIN TableB b ON a.ID = b.InvoiceID
    WHERE a.CustomerID = 11
    

    我还在Payment 周围添加了一个ISNULL(),以防止null 超出您的owed 金额。如果需要(或可能从其他表中),也可以将其添加到 InvoiceVal 以说明尚未开具发票的 CustomerID。

    如果你想获得 ALL CustomerIDs,你必须在你的分区中考虑到这一点。

    SELECT s1.CustomerID, aid AS InvoiceID, s1.bid, s1.Payment
        , (s1.StartInvoice - s1.runningPayment) AS Owed
    FROM (
        SELECT a.ID AS aid, a.CustomerID, a.InvoiceVal AS StartInvoice
          , b.ID AS bid, b.Payment
          , ISNULL(SUM(b.Payment) OVER (PARTITION BY a.CustomerID, a.ID ORDER BY b.id),0) AS runningPayment
        FROM TableA a 
        LEFT OUTER JOIN TableB b ON a.ID = b.InvoiceID
    ) s1
    ORDER BY s1.CustomerID, s1.aid, s1.bid
    

    Fiddle 表明多付或支付 0 欠款的总余额。

    【讨论】:

    • 我刚刚注意到我的单一客户 ID 答案与 Simonare 的几乎相同。如果您需要No. 列来跟踪付款号码,请添加ROW_NUMBER() 窗口功能。主要区别在于 LEFT JOIN 而不是 INNER JOIN 以防止在有人未付款时排除 Owed 金额。
    • 另请注意,您的付款目前仅由ID 订购,因此如果您添加一行来说明付款日期,那么这可能是一种更好的排序方式总计。
    猜你喜欢
    • 2013-06-09
    • 2018-02-07
    • 1970-01-01
    • 2021-04-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-17
    • 2016-10-12
    • 2014-08-15
    相关资源
    最近更新 更多