I'm creating an SQL statement that will return a month by month summary on sales.
The summary will list some simple columns for the date, total number of sales and the total value of sales.
However, in addition to these columns, i'd like to include 3 more that will list the months best customer by amount spent. For these columns, I need some kind of inline subquery that can return their ID, Name and the Amount they spent.
My current effort uses an inline SELECT
statement, however, from my knowledge on how to implement these, you can only return one column and row per in-line statement.
To get around this with my scenario, I can of course create 3 separate in-line statements, however, besides this seeming impractical, it increases the query time more that necessary.
SELECT DATE_FORMAT(OrderDate,'%M %Y') AS OrderMonth, COUNT(OrderID) AS TotalOrders, SUM(OrderTotal) AS TotalAmount, (SELECT SUM(OrderTotal) FROM Orders WHERE DATE_FORMAT(OrderDate,'%M %Y') = OrderMonth GROUP BY OrderCustomerFK ORDER BY SUM(OrderTotal) DESC LIMIT 1) AS TotalCustomerAmount, (SELECT OrderCustomerFK FROM Orders WHERE DATE_FORMAT(OrderDate,'%M %Y') = OrderMonth GROUP BY OrderCustomerFK ORDER BY SUM(OrderTotal) DESC LIMIT 1) AS CustomerID, (SELECT CustomerName FROM Orders INNER JOIN Customers ON OrderCustomerFK = CustomerID WHERE DATE_FORMAT(OrderDate,'%M %Y') = OrderMonth GROUP BY OrderCustomerFK ORDER BY SUM(OrderTotal) DESC LIMIT 1) AS CustomerName FROM Orders GROUP BY DATE_FORMAT(OrderDate,'%m%y') ORDER BY DATE_FORMAT(OrderDate,'%y%m') DESC
How can i better structure this query?
After some tweaking of Dave Barkers solution, I have a final version for anyone in the future looking for help.
The solution by Dave Barker worked perfectly with the customer details, however, it made the simpler Total Sales and Total Sale Amount columns get some crazy figures.
SELECT Y.OrderMonth, Y.TotalOrders, Y.TotalAmount, Z.OrdCustFK, Z.CustCompany, Z.CustOrdTotal, Z.CustSalesTotal FROM (SELECT OrdDate, DATE_FORMAT(OrdDate,'%M %Y') AS OrderMonth, COUNT(OrderID) AS TotalOrders, SUM(OrdGrandTotal) AS TotalAmount FROM Orders WHERE OrdConfirmed = 1 GROUP BY DATE_FORMAT(OrdDate,'%m%y') ORDER BY DATE_FORMAT(OrdDate,'%Y%m') DESC) Y INNER JOIN (SELECT DATE_FORMAT(OrdDate,'%M %Y') AS CustMonth, OrdCustFK, CustCompany, COUNT(OrderID) AS CustOrdTotal, SUM(OrdGrandTotal) AS CustSalesTotal FROM Orders INNER JOIN CustomerDetails ON OrdCustFK = CustomerID WHERE OrdConfirmed = 1 GROUP BY DATE_FORMAT(OrdDate,'%m%y'), OrdCustFK ORDER BY SUM(OrdGrandTotal) DESC) Z ON Z.CustMonth = Y.OrderMonth GROUP BY DATE_FORMAT(OrdDate,'%Y%m') ORDER BY DATE_FORMAT(OrdDate,'%Y%m') DESC
Yes, you can do this. The knack you need is the concept that there are two ways of getting tables out of the table server.
You may use the IN, ANY, or ALL operator in outer query to handle a subquery that returns multiple rows. Contents: Using IN operator with a Multiple Row Subquery. Using NOT IN operator with a Multiple Row Subquery.
Single Row Sub Query Although this query type is formally called "single-row," the name implies that the query returns multiple columns-but only one row of results. However, a single-row subquery can return only one row of results consisting of only one column to the outer query.
Move the inline SQL to be a inner join query. So you'd have something like...
SELECT DATE_FORMAT(OrderDate,'%M %Y') AS OrderMonth, COUNT(OrderID) AS TotalOrders, SUM(OrderTotal) AS TotalAmount, Z.OrderCustomerFK, Z.CustomerName, z.OrderTotal as CustomerTotal FROM Orders INNER JOIN (SELECT DATE_FORMAT(OrderDate,'%M %Y') as Mon, OrderCustomerFK, CustomerName, SUM(OrderTotal) as OrderTotal FROM Orders GROUP BY DATE_FORMAT(OrderDate,'%M %Y'), OrderCustomerFK, CustomerName ORDER BY SUM(OrderTotal) DESC LIMIT 1) Z ON Z.Mon = DATE_FORMAT(OrderDate,'%M %Y') GROUP BY DATE_FORMAT(OrderDate,'%m%y'), Z.OrderCustomerFK, Z.CustomerName ORDER BY DATE_FORMAT(OrderDate,'%y%m') DESC
You can also do something like:
SELECT a.`y`, ( SELECT @c:=NULL ) AS `temp`, ( SELECT @d:=NULL ) AS `temp`, ( SELECT CONCAT(@c:=b.`c`, @d:=b.`d`) FROM `b` ORDER BY b.`uid` LIMIT 1 ) AS `temp`, @c as c, @d as d FROM `a`
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With