Skip to content
Reliable Data Engineering
Practice problem easy window-functionsaggregationpercent-of-total
Solve it in the browser (SQL editor)

Category Share of Revenue

Difficulty: Easy · Topics: window-functions, aggregation, percent-of-total · Asked at: Amazon, Walmart, Instacart

Problem

For each (category, product), return total revenue, its share of the category’s revenue (pct_of_category), and its share of all revenue (pct_of_total), both as percentages rounded to 1 decimal. Order by category, then revenue descending.

Schema and sample data

CREATE TABLE sales (product TEXT, category TEXT, revenue INTEGER);
INSERT INTO sales VALUES
('laptop','electronics',1200),('laptop','electronics',800),('phone','electronics',1000),
('desk','furniture',400),('chair','furniture',150),('chair','furniture',50),('lamp','furniture',400);

Expected output

categoryproductrevenuepct_of_categorypct_of_total
electronicslaptop200066.750.0
electronicsphone100033.325.0
furnituredesk40040.010.0
furniturelamp40040.010.0
furniturechair20020.05.0

Hints

Hint 1

Aggregate to product level first with GROUP BY, then apply window functions on the aggregated result.

Hint 2

SUM(SUM(revenue)) OVER (...) is legal: the inner SUM is the GROUP BY aggregate.

Solution

SELECT category, product,
       SUM(revenue) AS revenue,
       ROUND(100.0 * SUM(revenue) / SUM(SUM(revenue)) OVER (PARTITION BY category), 1) AS pct_of_category,
       ROUND(100.0 * SUM(revenue) / SUM(SUM(revenue)) OVER (), 1)                      AS pct_of_total
FROM sales
GROUP BY category, product
ORDER BY category, revenue DESC, product;

Explanation

Window functions run after GROUP BY, so they can aggregate the aggregates. OVER () with an empty window spans all grouped rows. 100.0 * avoids integer division.

Follow-up questions

Return only products that make up the top 80% of each category’s revenue.

Add a running share: SUM(SUM(revenue)) OVER (PARTITION BY category ORDER BY SUM(revenue) DESC ROWS UNBOUNDED PRECEDING) / SUM(SUM(revenue)) OVER (PARTITION BY category) and keep rows where the previous running share is < 0.8.