Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Funções agregadas em várias tabelas que não fornecem resultados corretos


Ao adicionar outra tabela, você pode afetar o número de linhas e, quando isso acontecer, as agregações também serão afetadas. Para evitar essa agregação da tabela de detalhes para que possa haver apenas uma linha por pedido, as outras agregações permanecerão consistentes.
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

EDITAR


Não use "23:59" como ponto final para um período, pois isso não é preciso e pode levar a resultados incorretos. Existe uma alternativa muito simples e mais precisa que requer apenas que você pare de usar "entre". Além disso, '31/12/2015 23:59' é NÃO uma maneira segura de especificar um valor de data/hora. Use '20160101' que É o formato literal mais seguro no 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'