Sql 基于集合的方法将付款应用于票据

Sql 基于集合的方法将付款应用于票据,sql,sql-server,sql-server-2005,Sql,Sql Server,Sql Server 2005,我正在尝试显示应用于账单的付款,我想知道是否有一种方法可以做到这一点,而不使用游标和命令逻辑。我有账单表和付款表。付款不总是账单金额,有时超过,有时低于。我正在尝试创建某种类型的联接,以显示每个付款中有多少应用于每个账单 假设: 票据属于单一账户 付款按票据ID的顺序应用于每张票据 给定一个Bills表: ID Amount 1 500 2 500 3 500 情景1: 付款表 ID Amount 1 750 2 750 通过上述账单表和场景1付款表,我希望看到以下输

我正在尝试显示应用于账单的付款,我想知道是否有一种方法可以做到这一点,而不使用游标和命令逻辑。我有账单表和付款表。付款不总是账单金额,有时超过,有时低于。我正在尝试创建某种类型的联接,以显示每个付款中有多少应用于每个账单

假设:

票据属于单一账户 付款按票据ID的顺序应用于每张票据 给定一个Bills表:

ID  Amount
1   500
2   500
3   500
情景1:

付款表

ID  Amount
1   750
2   750
通过上述账单表和场景1付款表,我希望看到以下输出:

Bill ID | Payment ID | Amount Applied
1   1   500
2   2   250
3   2   500
3   2   250
情景2:

Payments table:
1   300
2   300
3   300
4   300
5   300
鉴于上述账单表和场景2付款表,我希望看到输出:

Bill ID | Payment ID | Amount Applied
1   1   300
1   2   200
2   2   100
2   3   300
2   4   100
3   4   200
3   5   300
我可以使用游标来实现这一点,但我想知道是否有人知道如何使用基于集合的SQL来实现这一点


谢谢

SQL 2005还需要几个步骤,因为它缺少。。。和滞后函数,但基本思想是一样的:计算账单和付款的运行总数

每张账单可以是三种状态之一:未支付、全额支付或部分支付。比较运行总数将确定状态。当前状态和以前状态之间的差异将是当前周期中应用于该票据的付款金额

SQL 2005

SQL 2008+

使用有序窗口函数,可以提高查询效率

WITH
  Bills_Payments_RunningTotal AS (
    SELECT
       b_ID = b.ID
      ,p_ID = p.ID
      ,b_Amount = b.Amount
      ,p_Amount = p.Amount
      ,b_RunningTotal = SUM(b.Amount) OVER(PARTITION BY p.ID ORDER BY b.ID)
      ,p_RunningTotal = SUM(p.Amount) OVER(PARTITION BY b.ID ORDER BY p.ID)
    FROM Bills b
    CROSS JOIN Payments p
  )
 ,Bills_Payments_RemainderDue AS (
    SELECT b_ID,p_ID,b_Amount,p_Amount
     ,b_Current_Remainder_Due = CASE
        WHEN b_RunningTotal < p_RunningTotal THEN 0
        WHEN b_RunningTotal > p_RunningTotal + b_Amount THEN b_Amount
        ELSE b_RunningTotal - p_RunningTotal
      END
    FROM Bills_Payments_RunningTotal
  )
 ,Bills_Payments_AmountApplied AS (
    SELECT 
      [Bill ID] = b_ID
     ,[Payment ID] = p_ID
     ,[Amount Applied] = ISNULL(LAG(b_Current_Remainder_Due) OVER(PARTITION BY b_ID ORDER BY p_ID),b_Amount) - b_Current_Remainder_Due
    FROM Bills_Payments_RemainderDue
  )
SELECT [Bill ID],[Payment ID],[Amount Applied]
FROM Bills_Payments_AmountApplied
WHERE [Amount Applied] > 0
ORDER BY [Bill ID],[Payment ID]

我只能考虑使用递归CTE,但还没有弄清楚如何应用它,因为没有将付款与账单关联起来的表?您能更改表吗?通常情况下,您的付款表与账单表之间有一个多对一的关系。它应该只需要两个表来表示您的数据-正确地规范化。我不会尝试这样做,因为这将有一个与账单相关的表。输入付款后,您可以确定要将其应用于哪些票据,并在此时维护该表。在我看来,这是要存储的东西,而不是每次显示时都要计算的东西。这里有一个例子,付款是通过基于集合的方法映射到费用的。我认为您可以转换脚本,这对您的情况很有用
WITH
  Bills_Payments_RunningTotal AS (
    SELECT
       b_ID = b.ID
      ,p_ID = p.ID
      ,b_Amount = b.Amount
      ,p_Amount = p.Amount
      ,b_RunningTotal = SUM(b.Amount) OVER(PARTITION BY p.ID ORDER BY b.ID)
      ,p_RunningTotal = SUM(p.Amount) OVER(PARTITION BY b.ID ORDER BY p.ID)
    FROM Bills b
    CROSS JOIN Payments p
  )
 ,Bills_Payments_RemainderDue AS (
    SELECT b_ID,p_ID,b_Amount,p_Amount
     ,b_Current_Remainder_Due = CASE
        WHEN b_RunningTotal < p_RunningTotal THEN 0
        WHEN b_RunningTotal > p_RunningTotal + b_Amount THEN b_Amount
        ELSE b_RunningTotal - p_RunningTotal
      END
    FROM Bills_Payments_RunningTotal
  )
 ,Bills_Payments_AmountApplied AS (
    SELECT 
      [Bill ID] = b_ID
     ,[Payment ID] = p_ID
     ,[Amount Applied] = ISNULL(LAG(b_Current_Remainder_Due) OVER(PARTITION BY b_ID ORDER BY p_ID),b_Amount) - b_Current_Remainder_Due
    FROM Bills_Payments_RemainderDue
  )
SELECT [Bill ID],[Payment ID],[Amount Applied]
FROM Bills_Payments_AmountApplied
WHERE [Amount Applied] > 0
ORDER BY [Bill ID],[Payment ID]