Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Funzioni aggregate su più tabelle che non danno risultati corretti

Quando aggiungi un'altra tabella puoi influenzare il numero di righe e quando ciò accade anche le aggregazioni saranno interessate. Per evitare questo aggregare la tabella dei dettagli in modo che possa esserci solo una riga per ordine, le altre aggregazioni rimarranno coerenti.

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

MODIFICA

Non utilizzare "23:59" come punto finale per un intervallo di date, che non è accurato e può portare a risultati errati. C'è un'alternativa molto semplice e più accurata che richiede solo di smettere di usare "tra". Inoltre "31/12/2015 23:59" è NON un modo sicuro per specificare un valore di data/ora. Utilizza "20160101" che SI il formato letterale più sicuro in 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'