Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Aggregierte Funktionen in mehreren Tabellen liefern keine korrekten Ergebnisse

Wenn Sie eine weitere Tabelle hinzufügen, können Sie die Anzahl der Zeilen beeinflussen, und wenn dies geschieht, werden auch Aggregationen beeinflusst. Um dies zu vermeiden, aggregieren Sie die Detailtabelle so, dass es nur eine Zeile pro Bestellung geben kann, dann bleiben die anderen Aggregationen konsistent.

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

BEARBEITEN

Bitte verwenden Sie nicht "23:59" als Endpunkt für einen Datumsbereich, da dies nicht genau ist und zu falschen Ergebnissen führen kann. Es gibt eine sehr einfache und genauere Alternative, bei der Sie nur aufhören müssen, "zwischen" zu verwenden. Außerdem ist '31.12.2015 23:59' NICHT eine sichere Möglichkeit, einen Datums-/Uhrzeitwert anzugeben. Verwenden Sie „20160101“, was IST das sicherste wörtliche Format 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'