Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Les fonctions d'agrégation sur plusieurs tables ne donnent pas de résultats corrects

Lorsque vous ajoutez une autre table, vous pouvez affecter le nombre de lignes et lorsque cela se produit, les agrégations seront également affectées. Pour éviter cela, agrégez le tableau de détail afin qu'il ne puisse y avoir qu'une seule ligne par commande, les autres agrégations resteront cohérentes.

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

MODIFIER

Veuillez ne pas utiliser "23:59" comme point final pour une plage de dates, ce n'est pas exact et peut conduire à des résultats incorrects. Il existe une alternative très simple et plus précise qui vous demande simplement d'arrêter d'utiliser "entre". De plus, '12/31/2015 23:59' n'est PAS un moyen sûr de spécifier une valeur de date/heure. Utilisez '20160101' qui EST le format littéral le plus sûr dans 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'