Reputation: 341
Will my code work for solving the following problem? The total cost of all items ordered for all orders placed in July, 1996. Looking at 2 tables (Orders
and OrderDetails
) this is what I have so far.
SELECT
Orders.OrderID, Customers.ContactName, Orders.OrderDate
FROM
Customers
INNER JOIN
Orders ON Customers.CustomerID = Orders.CustomerID
INNER JOIN
[Order Details] ON Orders.OrderID = [Order Details].OrderID
WHERE
(Orders.OrderDate BETWEEN CONVERT(DATETIME, '1996-07-01 00:00:00', 102) AND CONVERT(DATETIME, '1996-07-31 00:00:00', 102))
AND SUM(Quantity * UnitPrice) AS grand_total;
The intent is to find the sum of each row and keep that number then sum the rows to produce a grand total. When I run the query it definitely doesn't produce what should be.
Upvotes: 1
Views: 8751
Reputation: 1
Try this:
SELECT
o.OrderID, c.ContactName, o.OrderDate, SUM(od.Quantity * od.UnitPrice) AS grand_total
FROM
dbo.Customers c
INNER JOIN
dbo.Orders o ON c.CustomerID = o.CustomerID
INNER JOIN
dbo.[Order Details] od ON o.OrderID = od.OrderID
WHERE
o.OrderDate BETWEEN {ts '1996-07-01 00:00:00.000'} AND {ts '1996-07-31 23:59:59.997'}
GROUP BY
GROUPING SETS ((o.OrderID, c.ContactName, o.OrderDate), ())
GROUPING SETS ((o.OrderID, c.ContactName, o.OrderDate), ...)
will group the source rows by o.OrderID, c.ContactName, o.OrderDate
and, also, will compute the SUM
for every OrderID, ContactName, OrderDate
pair of values.
GROUPING SETS ((...), ())
instructs SQL Server to compute, also, the grand total (total of all order totals):
SELECT OrderID, SUM(OrderDetailValue) AS OrderTotal
FROM (
SELECT 11, 1, 'A', 1 UNION ALL
SELECT 12, 1, 'B', 10 UNION ALL
SELECT 13, 2, 'A', 100
) AS Orders(OrderDetailID, OrderID, ProductName, OrderDetailValue)
GROUP BY GROUPING SETS ((OrderID), ());
Results:
OrderID OrderTotal
------- ----------
1 11 <-- Total generated by GROUPING SETS ((OrderID), ...)
2 100 <-- Total generated by GROUPING SETS ((OrderID), ...)
NULL 111 <-- Total generated by GROUPING SETS (..., ())
Upvotes: 3
Reputation: 69514
;WITH CTE
AS(
SELECT Orders.OrderID
, Customers.ContactName
, Orders.OrderDate
, SUM(Quantity * UnitPrice) AS grand_total
, rn = ROW_NUMBER() OVER (ORDER BY Orders.OrderID)
FROM Customers INNER JOIN
Orders ON Customers.CustomerID = Orders.CustomerID INNER JOIN
[Order Details] ON Orders.OrderID = [Order Details].OrderID
WHERE MONTH(Orders.OrderDate) = 7 AND YEAR(Orders.OrderDate) = 1996
GROUP BY Orders.OrderID
, Customers.ContactName
, Orders.OrderDate
)
SELECT A.OrderID
, A.ContactName
, A.OrderDate
, A.grand_total
, (SELECT SUM(grand_total)
FROM CTE B
WHERE B.grand_total > A.grand_total) RunningTotal
FROM CTE A
ORDER BY RunningTotal
Result Set
╔═════════╦═════════════════════╦═════════════════════════╦═════════════╦══════════════╗
║ OrderID ║ ContactName ║ OrderDate ║ grand_total ║ RunningTotal ║
╠═════════╬═════════════════════╬═════════════════════════╬═════════════╬══════════════╣
║ 10267 ║ Peter Franken ║ 1996-07-29 00:00:00.000 ║ 4031.00 ║ NULL ║
║ 10252 ║ Pascale Cartrain ║ 1996-07-09 00:00:00.000 ║ 3730.00 ║ 4031.00 ║
║ 10255 ║ Michael Holz ║ 1996-07-12 00:00:00.000 ║ 2490.50 ║ 7761.00 ║
║ 10263 ║ Roland Mendel ║ 1996-07-23 00:00:00.000 ║ 2464.80 ║ 10251.50 ║
║ 10258 ║ Roland Mendel ║ 1996-07-17 00:00:00.000 ║ 2018.60 ║ 12716.30 ║
║ 10249 ║ Karin Josephs ║ 1996-07-05 00:00:00.000 ║ 1863.40 ║ 14734.90 ║
║ 10250 ║ Mario Pontes ║ 1996-07-08 00:00:00.000 ║ 1813.00 ║ 16598.30 ║
║ 10260 ║ Henriette Pfalzheim ║ 1996-07-19 00:00:00.000 ║ 1746.20 ║ 18411.30 ║
║ 10253 ║ Mario Pontes ║ 1996-07-10 00:00:00.000 ║ 1444.80 ║ 20157.50 ║
║ 10265 ║ Frédérique Citeaux ║ 1996-07-25 00:00:00.000 ║ 1176.00 ║ 21602.30 ║
║ 10257 ║ Carlos Hernández ║ 1996-07-16 00:00:00.000 ║ 1119.90 ║ 22778.30 ║
║ 10268 ║ Manuel Pereira ║ 1996-07-30 00:00:00.000 ║ 1101.20 ║ 23898.20 ║
║ 10264 ║ Maria Larsson ║ 1996-07-24 00:00:00.000 ║ 724.50 ║ 24999.40 ║
╚═════════╩═════════════════════╩═════════════════════════╩═════════════╩══════════════╝
Upvotes: 0
Reputation: 14915
There are many ways to do this.
GROUP BY ROLLUP - http://technet.microsoft.com/en-us/library/ms177673.aspx
GROUPING SETS - http://technet.microsoft.com/en-us/library/bb522495(v=SQL.105).aspx
OVER - http://technet.microsoft.com/en-us/library/ms189461.aspx
Do not use Shiva's solution since COMPUTE is defunct in SQL Server 2012!
Here are some issues that I corrected in my solution.
1 - Use table alias's
2 - Do not use between or convert on date ranges.
It will not be SARGABLE.
Since you were not specific, I chose a simple sum by each customers order id with a total month to-date for the customer regardless of the order id.
To solve this, I used a OVER clause. Since I did not have test data or tables from you, It is your homework to check the solution for syntax errors.
-- Customer sum by order id, total sum by customer.
SELECT
C.ContactName,
O.OrderID,
O.OrderDate,
SUM(D.Quantity * D.UnitPrice) AS OrderTotal,
SUM(D.Quantity * D.UnitPrice) OVER (PARTITION BY C.ContactName) as CustomerTotal
FROM Customers as c INNER JOIN Orders as O
ON C.CustomerID = O.CustomerID
INNER JOIN [Order Details] D
ON O.OrderID = D.OrderID
WHERE
O.OrderDate >= '1996-07-01 00:00:00' AND
O.OrderDate < '1996-08-01 00:00:00'
GROUP BY
C.ContactName,
O.OrderID,
O.OrderDate
Upvotes: 1