Question

This is the code I have to optimize, I managed to get it to half of the starting cost only with indexes and changing the LIKE for a SUBSTRING sentence. My problem is now with the sub-query in the last line, and the SUM lines in the select, I believe I have to get rid of those by creating a new table or column but can't get it done.

SELECT 
C.LastName as Customer , e.LastName as SalesPerson, s.ProductID,
p.Name as ProductName, SUM( s.Quantity ) as quantity, 
SUM ( p.Price * s.Quantity ) as amount 
FROM dbo.Sales s, dbo.Customers c, dbo.Employees e, dbo.Products p 
WHERE 
 s.CustomerID = c.CustomerID and 
 s.ProductID = p.ProductID and 
 s.SalesPersonID = e.EmployeeID and
 p.Name like 'Paint%' 
GROUP BY C.LastName , e.LastName , s.ProductID, p.Name 
HAVING sum ( s.Quantity ) < 
(select AVG(s2.Quantity) from dbo.Sales s2 where s2.ProductID=s.ProductID ) 

Any help is welcome, thanks in advance.

Was it helpful?

Solution

Can't test it right now, but I think this should work:

SELECT c.LastName as Customer , 
       e.LastName as SalesPerson, 
       s.ProductID,
       p.Name as ProductName, 
       SUM(s.Quantity) as quantity, 
       SUM(p.Price * s.Quantity) as amount 
  FROM dbo.Sales s, 
  JOIN dbo.Customers c
    ON c.CustomerID = s.CustomerID 
  JOIN dbo.Employees e
    ON e.EmployeeID = s.SalesPersonID
  JOIN dbo.Products p 
    ON p.ProductID = s.ProductID
   AND p.Name like 'Paint%'
  JOIN (SELECT ProductID,
               AVG(Quantity) as avg_Quantity
          FROM dbo.Sales) s2 
    ON s2.ProductID = s.ProductID
 GROUP BY c.LastName , e.LastName , s.ProductID, p.Name 
HAVING sum(s.Quantity) <  AVG(s2.avg_Quantity) 

OTHER TIPS

If using SQL Server you can streamline this a little with window functions:

WITH cte AS (   SELECT  C.LastName AS Customer
                      , e.LastName AS SalesPerson
                      , s.ProductID
                      , p.Name AS ProductName
                      , SUM(s.Quantity) AS quantity
                      , SUM(p.Price * s.Quantity) AS amount
                      , SUM(SUM(s.Quantity)) OVER (PARTITION BY s.ProductID)*1.0/SUM(COUNT(*)) OVER (PARTITION BY s.ProductID) AS Avg_Qty
                FROM     dbo.Sales s
                    JOIN dbo.Customers c ON s.CustomerID = c.CustomerID
                    JOIN dbo.Employees e ON s.SalesPersonID = e.EmployeeID
                    JOIN dbo.Products p ON s.ProductID = p.ProductID
                WHERE   s.Name LIKE 'Paint%'
                GROUP BY C.LastName
                      , e.LastName
                      , s.ProductID
                      , p.Name
            )
SELECT * 
FROM  cte
WHERE quantity < Avg_Qty

Adding a Name_Category field or similar to avoid using LIKE would help.

This is equal to your statement but much faster:

SELECT 
C.LastName as Customer , e.LastName as SalesPerson, s.ProductID,
p.Name as ProductName, SUM( s.Quantity ) as quantity, 
SUM ( p.Price * s.Quantity ) as amount 
FROM dbo.Sales s
INNER JOIN dbo.Products p ON s.ProductID = p.ProductID /*AND p.Name like 'Paint%' --optionally place filter here if you like*/
INNER JOIN (SELECT s2.ProductID SalesProductID, AVG(s2.Quantity)AVG_Quantity FROM dbo.Sales s2 GROUP BY s2.ProductID)ProductSales ON ProductSales.SalesProductID = s.ProductID
INNER JOIN dbo.Customers c ON s.CustomerID = c.CustomerID
INNER JOIN dbo.Employees e ON s.SalesPersonID = e.EmployeeID
WHERE p.Name like 'Paint%' 
GROUP BY C.LastName , e.LastName , s.ProductID, p.Name 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top