Top 3 Revenue Months

A medium SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.

Domain
SQL
Difficulty
medium
Seniority
L3
Asked in
OnDeck

Problem

Finance is drawing up a short leaderboard of the strongest sales months. Find the three highest-grossing months by total transaction amount, biggest earner first, with each month shown as YYYY-MM.

The three best months on record.

Tables

transactions

Columns: transaction_id INTEGER, user_id INTEGER, product_id INTEGER, quantity INTEGER, total_amount REAL, transaction_date TEXT

transactions: 10 of 200 rows
transaction_iduser_idproduct_idquantitytotal_amounttransaction_date
10671971001223.462026-02-02
11342941050336.932026-03-03
12013911099450.42026-04-04
12684881148563.872026-05-05
13355851197002026-06-06
14026821246290.812026-07-07
146977912953104.282026-08-08
153687613444117.752026-09-09
160397313935-452026-01-10
1670107014421144.692026-02-11

Expected output

First 3 of 3 rows
year_monthtotal_sales
2026-0110187.37
2026-099801.33
2026-029447.63

Worked solution and explanation

What this really is

This is a calendar rollup dressed up as a finance leaderboard. transaction_date is stored per day, so the month you are asked to rank is not a column: you derive it, sum total_amount across it, then cut to three. Anyone can write the descending sort and the cap. What separates candidates is building the month key first. Group on the raw date and you rank single days: a month's gross stays split across its day-rows, one big day can beat a strong month, and the output shows full dates instead of YYYY-MM.

The second decision is the year. transactions spans 2022 through 2026, so a key built from the month number alone pours every January into one bucket and inflates it with four years of sales.


Build it

Step 1: Derive a year-month key

strftime('%Y-%m', transaction_date) keeps February 2025 and February 2026 apart, and it is already in the YYYY-MM shape the leaderboard shows, so one expression is both the bucket and the label.

Step 2: Sum the revenue per month

SUM(total_amount) per bucket. The table holds a refund stored as a negative amount and a voided sale at zero; both stay in, so each month's total is what was actually booked. Do not reach for quantity: total_amount is already the line revenue.

Step 3: Sort and cut

ORDER BY total_sales DESC LIMIT 3. The cut is clean on this data because the third and fourth months do not tie. If the interviewer wants ties at third kept, swap the cap for DENSE_RANK() and keep rnk <= 3.

Step 4: Name the output

Alias the key year_month and the sum total_sales. The alias also lets GROUP BY year_month reuse the expression instead of repeating it.

The solution

Top three revenue months
SELECT
  strftime('%Y-%m', transaction_date) AS year_month,
  SUM(total_amount) AS total_sales
FROM transactions
GROUP BY year_month
ORDER BY total_sales DESC
LIMIT 3;
Group on the raw date
GROUP BY transaction_date makes one row per day. Its top three are the three biggest single days, labeled with full dates, and no month's revenue is ever added up.
Group on the month key
GROUP BY year_month collapses every day of a month into one row, so SUM(total_amount) is the month's gross and the cap picks the three strongest months.

Common follow-up questions

Common follow-up questions