多个表上的聚合函数未给出正确的结果

时间:2017-12-13 00:14:30

标签: sql-server-2008

我有以下查询,在两个表(客户和订单)上完成连接时效果很好。所有计算都是正确的。

   SELECT
         Customers.EmailAddress
         ,COUNT(Orders.OrderID)   AS 'overall NumOrders'
         ,SUM(Orders.PaymentAmount)  AS 'overall TotalOrdered'
           ,COUNT(case when Orders.OrderDate >= '20170101' then Orders.OrderID  end) AS '2017 NumOrders'
        ,SUM(  case when Orders.OrderDate >= '20170101' then Orders.PaymentAmount end) AS '2017 TotalOrdered'
       ,COUNT(case when Orders.OrderDate BETWEEN ' 01/01/2015 00:00' AND '12/31/2015 23:59' THEN Orders.OrderID   end) AS '2015 NumOrders'
        ,SUM(case when Orders.OrderDate BETWEEN ' 01/01/2015 00:00' AND '12/31/2015 23:59' then Orders.PaymentAmount end) AS '2015 TotalOrdered'
         FROM Customers
     JOIN Orders ON Customers.Customerid = Orders.Customerid
    WHERE
    Orders.OrderStatus NOT IN ('Cancelled','Payment Declined')
    AND Orders.OrderDate BETWEEN ' 01/01/2015 00:00' AND getdate()
    GROUP BY 
          Customers.EmailAddress

正确的结果:

Emailaddress|overallnumorders|overalltotalordered|2017numorder|2017totalordered| 2015numorder|2015totalordered
xyz@gmail.com 1                    23.99            0             0                      1               23.99

但是当我在上面的查询中添加3个表(customers,orders,orderdetails)时,我的值增加了一倍

SELECT
     Customers.EmailAddress
     ,COUNT(Orders.OrderID)   AS 'overall NumOrders'
     ,SUM(Orders.PaymentAmount)  AS 'overall TotalOrdered'
SUM((OrderDetails.Vendor_Price) * (OrderDetails.Quantity) ) AS TotalCost,
       ,COUNT(case when Orders.OrderDate >= '20170101' then Orders.OrderID  end) AS '2017 NumOrders'
    ,SUM(  case when Orders.OrderDate >= '20170101' then Orders.PaymentAmount end) AS '2017 TotalOrdered'
   ,COUNT(case when Orders.OrderDate BETWEEN ' 01/01/2015 00:00' AND '12/31/2015 23:59' THEN Orders.OrderID   end) AS '2015 NumOrders'
    ,SUM(case when Orders.OrderDate BETWEEN ' 01/01/2015 00:00' AND '12/31/2015 23:59' then Orders.PaymentAmount end) AS '2015 TotalOrdered'
     FROM Customers
 JOIN Orders ON Customers.Customerid = Orders.Customerid
JOIN Orderdetails ON Orders.Orderid=Orderdetails.Orderid
WHERE
Orders.OrderStatus NOT IN ('Cancelled','Payment Declined')
AND Orders.OrderDate BETWEEN ' 01/01/2015 00:00' AND getdate()
GROUP BY 
      Customers.EmailAddress

结果不正确:

    Emailaddress|overallnumorders|overalltotalordered|totalcost|2017numorder|2017totalordered| 2015numorder|2015totalordered
 xyz@gmail.com          2           47.98             11.99          0             0                      2               47.98

为什么在第三个表上进行连接是在改变计算?在哪里我想要正确的结果:

Emailaddress|overallnumorders|overalltotalordered|totalcost|2017numorder|2017totalordered| 2015numorder|2015totalordered
    xyz@gmail.com 1                    23.99      11.99      0             0                      1               23.99

1 个答案:

答案 0 :(得分:0)

当您添加另一个表时,您可以影响行数,当发生这种情况时,聚合也会受到影响。为避免这种情况聚合详细信息表,以便每个订单只能有一行,那么其他聚合将保持一致。

SELECT
      Customers.EmailAddress
    , COUNT(Orders.OrderID)                                                                                            AS 'overall NumOrders'
    , SUM(Orders.PaymentAmount)                                                                                        AS 'overall TotalOrdered'
    , SUM(od.totalcost) AS totalcost
    , COUNT(CASE WHEN Orders.OrderDate >= '20170101' THEN Orders.OrderID END)                                          AS '2017 NumOrders'
    , SUM(CASE WHEN Orders.OrderDate >= '20170101' THEN Orders.PaymentAmount END)                                      AS '2017 TotalOrdered'
    , COUNT(CASE WHEN Orders.OrderDate BETWEEN ' 01/01/2015 00:00' AND '12/31/2015 23:59' THEN Orders.OrderID END)     AS '2015 NumOrders'
    , SUM(CASE WHEN Orders.OrderDate BETWEEN ' 01/01/2015 00:00' AND '12/31/2015 23:59' THEN Orders.PaymentAmount END) AS '2015 TotalOrdered'
FROM Customers
JOIN Orders ON Customers.Customerid = Orders.Customerid
JOIN (
      SELECT
            Orderid
          , SUM((Vendor_Price) * (Quantity)) AS totalcost
      FROM OrderDetails
      GROUP BY
            Orderid
) od ON Orders.Orderid = od.Orderid
WHERE Orders.OrderStatus NOT IN ('Cancelled', 'Payment Declined')
AND Orders.OrderDate BETWEEN ' 01/01/2015 00:00' AND GETDATE()
GROUP BY
      Customers.EmailAddress

修改

请不要使用" 23:59"作为日期范围的终点,这不准确,可能导致错误的结果。有一个简单而准确的替代方案,只需要你停止使用"之间的#34;。另外' 12/31/2015 23:59'是指定日期/时间值的安全方式。使用' 20160101'哪个 IS 是SQL Server YYYYMMDD中最安全的文字格式。

    , COUNT(CASE WHEN Orders.OrderDate >= '20150101' AND Orders.OrderDate < '20160101' THEN Orders.OrderID END)     AS '2015 NumOrders'
    , SUM(CASE WHEN Orders.OrderDate >='20150101' AND Orders.OrderDate < '20160101' THEN Orders.PaymentAmount END) AS '2015 TotalOrdered'