Interview question
Return the top three products in each category
Aggregates product sales and ranks independently inside each category with a deterministic top-N rule.
TL;DR
Aggregates product sales and ranks independently inside each category with a deterministic top-N rule.
Aggregate-then-rank flow, partitioned windows, tie policy, date filtering, and top-N-per-group reasoning.
Practice the problem like a real interview: restate, reason, implement, and test.
Tables: Products(ProductId, CategoryId, Name), Orders(OrderId, Status, PaidAtUtc), and OrderLines(OrderId, ProductId, Quantity). Sum paid quantity per product and return at most three products per category. Break equal quantities by smaller ProductId.
Category A has quantities 20, 20, 15, and 4. The two products tied at 20 are ordered by product id, followed by 15. Exactly three rows are returned.
[FromUtc, ToUtc) contribute.I first aggregate to one row per category and product. Ranking raw order lines would rank purchases, not products. I then use ROW_NUMBER partitioned by category and order by quantity descending plus product id. ROW_NUMBER implements an exact three-row policy; if the product requirement were to include every tie, I would choose DENSE_RANK instead.
WITH ProductSales AS
(
SELECT
p.CategoryId,
p.ProductId,
p.Name,
SUM(ol.Quantity) AS PaidQuantity
FROM dbo.Orders AS o
INNER JOIN dbo.OrderLines AS ol ON ol.OrderId = o.OrderId
INNER JOIN dbo.Products AS p ON p.ProductId = ol.ProductId
WHERE o.Status = 'Paid'
AND o.PaidAtUtc >= @FromUtc
AND o.PaidAtUtc < @ToUtc
GROUP BY p.CategoryId, p.ProductId, p.Name
),
RankedProducts AS
(
SELECT
CategoryId,
ProductId,
Name,
PaidQuantity,
ROW_NUMBER() OVER
(
PARTITION BY CategoryId
ORDER BY PaidQuantity DESC, ProductId
) AS CategoryRank
FROM ProductSales
)
SELECT CategoryId, ProductId, Name, PaidQuantity, CategoryRank
FROM RankedProducts
WHERE CategoryRank <= 3
ORDER BY CategoryId, CategoryRank;
The joins and aggregation dominate the work; filters should narrow paid orders before ranking. Useful indexes depend on table sizes but commonly begin with the order date/status access path and the foreign keys used by line and product joins.
TOP (3) instead of partitioning by category.DENSE_RANK when the requirement says at most three rows.Move to the linked follow-up, next path step, prerequisite, or deeper variant.
Practice the next layer of the same subject.