PAYATHON 2026

如何计算 Partial Payment 和 Outstanding Payment

支付老李

结论

使用 LEFT JOIN 关联发票表和付款表,再通过条件聚合分别统计现金付款与部分付款。未付余额用发票金额减去该发票的全部付款金额计算。

SELECT
    i.InvDate,
    i.InvNo,
    i.InvAmount,
    SUM(CASE
            WHEN p.ResType = 'C' THEN p.ResAmount
            ELSE 0
        END) AS Cash,
    SUM(CASE
            WHEN p.ResType = 'P' THEN p.ResAmount
            ELSE 0
        END) AS Partial,
    i.InvAmount
        - COALESCE(SUM(p.ResAmount), 0) AS Balance
FROM Invoice AS i
LEFT JOIN Payment AS p
    ON p.InvNo = i.InvNo
GROUP BY
    i.InvDate,
    i.InvNo,
    i.InvAmount
ORDER BY
    i.InvDate,
    i.InvNo;

查询结果如下:

InvDate     InvNo  InvAmount  Cash  Partial  Balance
01/01/2016  T0001  3000       3000  0        0
02/01/2016  T0002  8000       0     4000     4000

计算原理

一张发票可能有多条付款记录,所以不能直接选择 ResAmount,而应按发票分组汇总:

  • ResType = 'C' 的金额计入 Cash。
  • ResType = 'P' 的金额计入 Partial。
  • Balance = InvAmount - 所有已付金额。
  • LEFT JOIN 会保留尚无付款记录的发票。
  • COALESCE(..., 0) 会在没有付款时把 NULL 转换为 0。

条件聚合的核心写法是:

SUM(CASE WHEN p.ResType = 'C' THEN p.ResAmount ELSE 0 END)

这段表达式只累计现金付款,其他付款类型按 0 处理。部分付款也按相同方式计算。

将无金额显示为 NULL

如果希望没有现金付款或部分付款时返回 NULL,再由报表界面显示为 -,可以省略 ELSE 0:

SELECT
    i.InvDate,
    i.InvNo,
    i.InvAmount,
    SUM(CASE
            WHEN p.ResType = 'C' THEN p.ResAmount
        END) AS Cash,
    SUM(CASE
            WHEN p.ResType = 'P' THEN p.ResAmount
        END) AS Partial,
    i.InvAmount
        - COALESCE(SUM(p.ResAmount), 0) AS Balance
FROM Invoice AS i
LEFT JOIN Payment AS p
    ON p.InvNo = i.InvNo
GROUP BY
    i.InvDate,
    i.InvNo,
    i.InvAmount
ORDER BY
    i.InvDate,
    i.InvNo;

此时空值会显示为:

InvDate     InvNo  InvAmount  Cash  Partial  Balance
01/01/2016  T0001  3000       3000  NULL     0
02/01/2016  T0002  8000       NULL  4000     4000

通常应让 SQL 返回数值或 NULL,再由展示层将 NULL 格式化为 -。如果直接在 SQL 中混用数字和字符串 '-',相关列可能被转换为字符串,影响后续排序和计算。

注意事项

如果 Payment 表中还有退款、冲销或其他不应计入已付金额的 ResType,余额就不能直接使用 SUM(p.ResAmount),而应明确限定付款类型:

i.InvAmount - COALESCE(
    SUM(
        CASE
            WHEN p.ResType IN ('C', 'P') THEN p.ResAmount
            ELSE 0
        END
    ),
    0
) AS Balance

还要确保 Invoice.InvNo 能唯一标识一张发票。如果发票编号只在特定客户、公司或账期内唯一,关联和分组条件也要加入相应字段,否则不同发票的付款可能会被汇总到一起。

备注:内容仅供参考。