SUM和GROUP BY问题

时间:2016-07-06 13:56:13

标签: mysql

我有桌子交付和桌面订单。可以将多个订单链接到交货。几天前,我问question 有关如何获得特定交货的订单金额总和,并迅速了解如何。 (再次感谢。)

现在我们也添加了一个结算表,就像订单一样,可以有多个结算链接到一个交货(通过交货ID,就像订单一样),我正在尝试获得价值的总和同样。我想我也会使用相同的策略和LEFT JOIN结算表,但问题是,当只有一个结算链接到特定的交付时,SUM(s.amount)返回实际值的两倍。

我试过玩GROUP BY无济于事。谁能告诉我我做错了什么?

提前致谢!

PS:这是我使用的查询,当只有一个结算时,它会返回结算金额的双倍值:

SELECT 
    d.id, 
    SUM(o.goods_amount) AS amount, 
    SUM(s.amount) AS settlementAmount, 
FROM delivery d 
LEFT JOIN order o 
    ON d.id = o.delivery_id 
LEFT JOIN settlement s 
    ON d.id = s.delivery_id 
WHERE d.id = *deliveryId*
GROUP BY d.id;

2 个答案:

答案 0 :(得分:1)

正如Spencer评论的那样,你得到了一种交叉加入的结果。让我们看一下这个样本数据。

Delivery Table
ID  Delivered_On
1   2016-07-01
2   2016-07-02

Orders Table
id  Deliveries_id  Amount
1   1              100
2   1              200
3   1              300
4   2              75

Now your Settlements table
Settlements Table
id  Delivery_id   Amount
1   1             525   (explicitly wrong amount to show result)
2   1             75 

您的查询是按照每个交付ID进行汇总,但是(左)加入了订单表和结算表。因此,每个表中存在的许多记录将被交叉连接,因此对于交货ID = 1,您有3个订单但是1个结算。因此,结算记录也将加入到每个订单表中,而不仅仅是交货表,从而得到3 * 525或$ 1575 PLUS 3 * 75 = 225美元的结果,总计1800美元。您的订单总和将恰好为600美元。

要解决此问题,您可能需要预先聚合每个辅助表,以便每次传递仅返回1个摘要记录并加入THOSE结果。为了防止查询所有订单和结算,我加入交货表以确定所有订单和日期范围内的相同日期范围。

SELECT 
      d.id AS delivery_id, 
      sumOrd.Amount as OrderAmount,
      sumStl.Amount as SettlementAmount
   from
      delivery d

         LEFT JOIN
         ( select 
                 d2.id,
                 SUM(o.amount) AS OrderAmount
              from
                 delivery d2
                    JOIN order o
                       ON d2.id = o.deliveries_id
              WHERE 
                     d2.delivered_on >= '2016-06-10' 
                 and d2.delivered_on < '2016-06-11'
              GROUP BY 
                 d2.id ) sumOrd
            on d.id = sumOrd.id

         LEFT JOIN
         ( select 
                 d2.id,
                 SUM(s.amount) AS SettlementAmount
              from
                 delivery d2
                    JOIN Settlement s
                       ON d2.id = s.delivery_id
              WHERE 
                     d2.delivered_on >= '2016-06-10' 
                 and d2.delivered_on < '2016-06-11'
              GROUP BY 
                 d2.id ) sumStl
            on d.id = sumStl.id
   where
          d.delivered_on >= '2016-06-10' 
      and d.delivered_on < '2016-06-11'

答案 1 :(得分:0)

首先使用以下查询验证您获得的结果是否正确

SELECT 
            d.id, 
            IFNULL(o.goods_amount,0) AS amount, 
            IFNULL(s.amount,0) AS settlementAmount, 
        FROM delivery d 
        LEFT JOIN order o 
            ON d.id = o.delivery_id 
        LEFT JOIN settlement s 
            ON d.id = s.delivery_id 
        WHERE d.id = *deliveryId*

然后请检查此查询

SELECT 
        d.id, 
        SUM(IFNULL(o.goods_amount,0)) AS amount, 
        SUM(IFNULL(s.amount,0)) AS settlementAmount, 
    FROM delivery d 
    LEFT JOIN order o 
        ON d.id = o.delivery_id 
    LEFT JOIN settlement s 
        ON d.id = s.delivery_id 
    WHERE d.id = *deliveryId*
    GROUP BY d.id;