SQL Query to return the Top 2 Values

328 views Asked by At

I am trying to return the top 2 most ordered items in our customer database. Below is what I have for the most ordered item but I am having trouble figuring out how to create another column for the 2nd most ordered item.

What is the best way to create the 2nd column?

SELECT FirstName, EmailAddress, Id, PreferredLocationId, 
(
     SELECT TOP 1 [Description] FROM [Order] o 
     INNER JOIN [OrderItem] oi ON oi.OrderId = o.OrderId
     WHERE o.CustomerId = Customer.Id
     GROUP BY [Description]
     ORDER BY COUNT(*) DESC
) AS MostOrderedItem
FROM Customer
GROUP BY FirstName, EmailAddress, Id, PreferredLocationId
1

There are 1 answers

2
Daniel Gimenez On BEST ANSWER

Lot's of different ways to handle this if you're using SQL Server 2012. I'm going to use a CTE to get the first two rows and use ROW_NUMBER()

WITH cte AS (
  SELECT CustomerId, [Description]
    , ROW_NUMBER() OVER (PARTITION BY CustomerId ORDER BY COUNT(*) DESC) [RowID]
  FROM [Order] o 
  INNER JOIN [OrderItem] oi ON oi.OrderId = o.OrderId
  GROUP BY CustomerId, [Description]
)
SELECT FirstName, EmailAddress, Id, PreferredLocationId, cte1.Description, cte2.Description
FROM Customer
LEFT JOIN cte cte1 ON cte1.CustomerID = Customer.CustomerId AND cte1.RowID = 1
LEFT JOIN cte cte2 ON cte2.CustomerID = Customer.CustomerId AND cte2.RowID = 2

The Common Table Expression creates the list of all customers, descriptions and their row number. Note that if you have ties, you're not guarunteed which description will come first. You can add to to the windowing function description so that if there is a tie, whatever comes first in the alphabet will be the tie breaker.