Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Funkcje agregujące na wielu tabelach nie dają poprawnych wyników

Gdy dodasz kolejną tabelę, możesz wpłynąć na liczbę wierszy, a gdy to nastąpi, wpłynie to również na agregacje. Aby uniknąć tego zagregowania tabeli szczegółów, tak aby w jednym zamówieniu mógł znajdować się tylko jeden wiersz, pozostałe agregacje pozostaną spójne.

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

EDYTUJ

Nie używaj „23:59” jako punktu końcowego dla zakresu dat, który jest niedokładny i może prowadzić do nieprawidłowych wyników. Istnieje bardzo prosta i dokładniejsza alternatywa, która wymaga po prostu zaprzestania używania „pomiędzy”. Dodatkowo „31.12.2015 23:59” to NIE bezpieczny sposób na określenie wartości daty/godziny. Użyj „20160101”, który JEST najbezpieczniejszy format literalny w 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'



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Aktualizowanie wartości ciągów w tabeli, która ma być przerzucana, takich jak ciąg YYYYMMDD do ciągu MMDDYYYY

  2. Nowe zmiany w kolumnach zawierających tylko metadane w SQL Server 2016

  3. Jak zrozumieć typ danych geograficznych serwera SQL?

  4. Generuj diagram relacji tabeli z istniejącego schematu (SQL Server)

  5. Geoserwer — połącz się z SQL Server 2008 Express i pobierz dane