You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过两张表计算客户待付款总额?SQL查询问题求助

统计客户待付款总额的正确SQL写法

需求与表结构

  • 需求:统计各客户的待付款总额,计算公式为 (发票表total_basic + freight_rate + delivery_rate) - 付款表payment_received总和
  • 发票表(invoice)结构:
inv_no  |  date |  customer_name | total_basic | freight_rate | delivery_rate 

(注:原表结构中字段名total_baic为笔误,统一修正为total_basic)

  • 付款表(payments)结构:
id | date | customer_name | payment_received | inv_no

遇到的问题

分别统计发票总金额和已收款的SQL可得到正确结果:

  • 发票总金额查询:
SELECT customer_name, 
       Sum(freight_rate) + sum(total_basic) + sum(delivery_rate) AS total_pending 
FROM invoice 
GROUP BY customer_name
  • 已收款查询:
SELECT customer_name, 
       Sum(payment_received) AS total_received 
FROM payments 
GROUP BY customer_name

但直接关联两张表查询时,出现金额翻倍错误:
错误SQL:

SELECT invoice.customer_name, 
       Sum(invoice.freight_rate)+Sum(invoice.total_basic)+Sum(invoice.delivery_rate) AS totalpending, 
       Sum(payments.payment_received) AS totalpayment 
FROM invoice, payments 
GROUP BY invoice.customer_name, payments.customer_name

错误结果:

customer_name | totalpending | totalpayment
John | 1800 | 1100

实际数据:John的发票仅有1笔(total_basic=600,其余运费、配送费为0),待付款应为600;付款有2笔(600+500=1100),但查询结果中发票总金额被错误计算为1800。

错误原因

未添加关联条件直接关联两张表,导致笛卡尔积:1条发票记录会与2条付款记录分别匹配,生成2条临时记录,统计时发票金额会被重复累加(若有N条付款记录,发票金额就会被累加N次),最终导致金额虚高。

正确SQL写法

先分别统计每个客户的发票总金额和收款总金额,再通过customer_name关联这两个统计结果,同时处理客户仅存在于其中一张表的情况(比如有发票未付款、或有付款无对应发票):

方法1:子查询关联

SELECT 
    COALESCE(i.customer_name, p.customer_name) AS customer_name,
    COALESCE(i.total_pending, 0) AS total_pending,
    COALESCE(p.total_received, 0) AS total_received,
    COALESCE(i.total_pending, 0) - COALESCE(p.total_received, 0) AS due_amount
FROM 
    (SELECT customer_name, 
            Sum(total_basic + freight_rate + delivery_rate) AS total_pending 
     FROM invoice 
     GROUP BY customer_name) i
FULL OUTER JOIN 
    (SELECT customer_name, 
            Sum(payment_received) AS total_received 
     FROM payments 
     GROUP BY customer_name) p
ON i.customer_name = p.customer_name
ORDER BY customer_name;

方法2:CTE(公共表表达式)写法

WITH invoice_totals AS (
    SELECT customer_name,
           SUM(total_basic + freight_rate + delivery_rate) AS total_pending
    FROM invoice
    GROUP BY customer_name
),
payment_totals AS (
    SELECT customer_name,
           SUM(payment_received) AS total_received
    FROM payments
    GROUP BY customer_name
)
SELECT 
    COALESCE(it.customer_name, pt.customer_name) AS customer_name,
    COALESCE(it.total_pending, 0) AS total_pending,
    COALESCE(pt.total_received, 0) AS total_received,
    COALESCE(it.total_pending, 0) - COALESCE(pt.total_received, 0) AS due_amount
FROM invoice_totals it
FULL OUTER JOIN payment_totals pt
ON it.customer_name = pt.customer_name
ORDER BY customer_name;

说明

  • COALESCE函数用于处理NULL值:如果某客户只有发票没有付款,total_received会被设为0;反之total_pending设为0,避免计算出现NULL。
  • FULL OUTER JOIN确保所有客户都被统计到,无论其是否有发票或付款记录。如果只需要统计有发票的客户,可改用LEFT JOIN;只需要有付款的客户则用RIGHT JOIN。

内容的提问来源于stack exchange,提问作者john Mac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 16:41:09