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

按客户分组统计采购额、已付款额的SQL查询问题求助

物料采购数据库统计查询问题解决方案

问题背景

正在搭建支持客户自主选择付款周期(如每周)的物料采购数据库,需生成无重复客户的统计报表,展示每位客户的采购总额、欠款额及已付款额。

涉及三个数据表:

  • Clients(客户信息表)
  • Payments(付款记录表)
  • OrdersInventory(采购物品及单价表)

表结构如下:

Clients    | Payments      | OrdersInventory | 
-----------| --------------|-----------------|
           | PaymentsID    | ItemID          |
ClientsID >|>ClientID      | Qty             |
           | PaymentAmount | NewPrice        |
           | OrderID      >|>OrderID         |

问题现象

同一客户有两笔付款记录(PaymentID 3为$10,PaymentID 4为$30),其中某订单包含两个物品,关联OrdersInventory表时,PaymentID 3的付款被重复显示:

ClientID | PaymentID | PaymentAmount | TotalItemsPrice
   1     |     3     |       $10     |    10
   1     |     3     |       $10     |    15
   1     |     4     |       $30     |    30

对TotalItemsPrice求和结果正确:

ClientID | PaymentID | PaymentAmount | TotalItemsPrice
   1     |     3     |       $10     |    25
   1     |     4     |       $30     |    30

但去除PaymentID后对PaymentAmount求和时,因关联导致重复计算,得到错误结果$50(期望为$40):

实际结果:

ClientID | SumOfPaymentAmount | TotalItemsPrice
   1     |       $50          |    $55

期望结果:

ClientID | SumOfPaymentAmount | TotalItemsPrice
   1     |       $40          |    $55

当前使用的SQL代码:

SELECT Clients.ClientID, Sum(Payments.PaymentAmount) AS SumOfPaymentAmount, Sum([NewPrice]*[Qty]) AS TotalItemsPrice
FROM Clients RIGHT JOIN (Payments INNER JOIN OrdersInventory ON Payments.OrderID = OrdersInventory.OrderID) ON Clients.ClientID = Payments.ClientID
GROUP BY Clients.ClientID;

解决方案

问题根源是多对多关联导致的重复行:一个付款对应多个订单物品,关联后付款记录被复制多次,直接求和会重复计算付款金额。以下是两种可行解决方法:

方案1:子查询分别聚合(推荐)

先分别对付款、订单物品按维度聚合,再关联结果,从根源避免重复行:

SELECT 
    c.ClientID,
    COALESCE(p.SumPayments, 0) AS SumOfPaymentAmount,
    COALESCE(o.TotalItemsPrice, 0) AS TotalItemsPrice,
    -- 直接计算欠款额
    COALESCE(o.TotalItemsPrice, 0) - COALESCE(p.SumPayments, 0) AS OutstandingAmount
FROM Clients c
LEFT JOIN (
    -- 按客户聚合付款总额
    SELECT ClientID, SUM(PaymentAmount) AS SumPayments
    FROM Payments
    GROUP BY ClientID
) p ON c.ClientID = p.ClientID
LEFT JOIN (
    -- 先按订单聚合单订单物品总价,再按客户聚合总采购额
    SELECT oi.ClientID, SUM(oi.OrderTotal) AS TotalItemsPrice
    FROM (
        SELECT 
            p.ClientID,
            oi.OrderID,
            SUM(oi.NewPrice * oi.Qty) AS OrderTotal
        FROM OrdersInventory oi
        JOIN Payments p ON oi.OrderID = p.OrderID
        GROUP BY p.ClientID, oi.OrderID
    ) oi
    GROUP BY oi.ClientID
) o ON c.ClientID = o.ClientID
WHERE c.ClientID IS NOT NULL; -- 仅保留有业务记录的客户

方案2:DISTINCT去重求和(简易场景)

若仅需统计已有关联记录的客户,可通过付款唯一标识(PaymentID)去重,避免重复计算付款金额:

SELECT 
    Clients.ClientID,
    -- 利用PaymentID唯一标识付款记录,避免重复求和
    SUM(DISTINCT Payments.PaymentAmount * Payments.PaymentID) / SUM(DISTINCT Payments.PaymentID) AS SumOfPaymentAmount,
    SUM([NewPrice]*[Qty]) AS TotalItemsPrice,
    SUM([NewPrice]*[Qty]) - (SUM(DISTINCT Payments.PaymentAmount * Payments.PaymentID) / SUM(DISTINCT Payments.PaymentID)) AS OutstandingAmount
FROM Clients 
RIGHT JOIN (Payments INNER JOIN OrdersInventory ON Payments.OrderID = OrdersInventory.OrderID) 
    ON Clients.ClientID = Payments.ClientID
GROUP BY Clients.ClientID;

注:此方法仅在PaymentID为唯一主键时有效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 00:03:34