views:

778

answers:

3

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?


FULL ANSWER

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
A: 

I guess you could use the IN command. For example,

SELECT * FROM products p WHERE p.id IN (3,4,5,6,...)

Hock
+1  A: 

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
Dave Barker
This code has given me a great base to work from, i'll try post the finished statement when complete.Cheers
ticallian
+1  A: 

Give this a shot:

  SELECT CONCAT(o.order_month, ' ', o.order_year),
         o.total_orders,
         o.total_amount,
         x.sum_order_total,
         x.ordercustomerfk,
         x.customername
    FROM (SELECT MONTH(t.orderdate) AS order_month,
                 YEAR(t.orderdate) AS order_year
                 COUNT(t.orderid) AS total_orders, 
                 SUM(t.ordertotal) AS total_amount
            FROM ORDERS t
        GROUP BY MONTH(t.orderdate), YEAR(t.orderdate)) o
    JOIN (SELECT MONTH(t.orderdate) AS ordermonth,
                 YEAR(t.orderdate) AS orderyear
                 SUM(t.ordertotal) 'sum_order_total',
                 t.ordercustomerfk,
                 c.customername
            FROM ORDERS t
            JOIN CUSTOMERS c ON c.customerid = o.ordercustomerfk
        GROUP BY t.ordercustomerfk, MONTH(t.orderdate), YEAR(t.orderdate)) x ON x.order_month = o.order_month
                                                                            AND x.order_year = o.order_year
ORDER BY o.order_year DESC, o.order_month DESC
OMG Ponies
Sorry, didn't notice your answer until I posted a revised version of Dave Barkers solution. However, it looks along the same lines as what finally worked for me so thanks.
ticallian