Regional Profits
An easy SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.
- Domain
- SQL
- Difficulty
- easy
- Seniority
- L3
Problem
Orders that were never tagged with a region have no place in a regional P&L, so the analyst building the quarterly deck wants them kept out of the breakdown of the orders table. For each region that remains, show its total profit and its number of orders, highest total profit first.
P&L by region. Before the board meeting.
Tables
orders
Columns: order_id INTEGER, status TEXT, region TEXT, profit REAL
| order_id | status | region | profit |
|---|---|---|---|
| 10097 | Pending | EU | 69.37 |
| 10194 | Cancelled | APAC | 88.74 |
| 10291 | Shipped | LATAM | 108.11 |
| 10388 | Processing | MEA | 127.48 |
| 10485 | Returned | US | 146.85 |
| 10582 | On Hold | EU | 166.22 |
| 10679 | Completed | APAC | 185.59 |
| 10776 | Pending | LATAM | 204.96 |
| 10873 | Cancelled | MEA | 224.33 |
| 10970 | Shipped | US | 243.7 |
Expected output
| region | total_profit | order_count |
|---|---|---|
| US | 31324.4 | 38 |
| APAC | 27668.88 | 36 |
| EU | 26959.64 | 36 |
| LATAM | 26911.32 | 36 |
| MEA | 26620.56 | 36 |
Worked solution and explanation
This is a filter-before-you-collapse problem wearing a P&L costume. Everyone writes SUM(profit) and COUNT(*) per region. What separates candidates is knowing that grouping does not skip a NULL key. Aggregates ignore NULL values, but GROUP BY collects every NULL region into one group of its own. Skip WHERE region IS NOT NULL and the deck grows a sixth line: a blank region carrying 17,076.30 of profit across 18 orders that belong to no market.
Three moves, in this order
Step 1: Drop untagged orders before grouping
18 of the 200 rows in orders have no region. Remove them in WHERE, while they are still rows, so they never form a group. HAVING region IS NOT NULL happens to run, but it says the wrong thing: these orders were never meant to be in the report, so remove them as orders rather than deleting a group after summing it.
Step 2: Collapse to one row per region
SUM(profit) gives the total and COUNT(*) gives the order count. Count rows, not a column: every order counts once whatever its status, and status is NULL on 14 of the remaining rows, so COUNT(status) would quietly undercount. The zero and negative profits are real P&L and stay in the sum.
Step 3: Sort on the computed total
ORDER BY total_profit DESC sorts on the aggregate's alias, so US at 31,324.40 leads and MEA closes the list. The five totals all differ, so no tiebreaker is needed.
SELECT region, SUM(profit) AS total_profit, COUNT(*) AS order_count
FROM orders
WHERE region IS NOT NULL
GROUP BY region
ORDER BY total_profit DESCSELECT region, SUM(profit) AS total_profit, COUNT(*) AS order_count
FROM orders
GROUP BY region
ORDER BY total_profit DESCRuns cleanly and returns six rows. The last has a NULL region, 17076.3 of profit and 18 orders.
- What aggregates do with NULL
SUM(profit)andCOUNT(profit)skip NULL values inside a group, so a missing number never moves a total.- What grouping does with NULL
GROUP BY regiontreats every NULLregionas the same key and emits one group for all of them, so a missing label becomes a row.
Common follow-up questions
- Finance now wants untagged orders shown as an 'Unassigned' line instead of dropped. What changes? (Tests replacing the filter with `COALESCE(region, 'Unassigned')` and knowing it still forms one group.)
- How would you add each region's share of total company profit to the same result? (Tests a window over the aggregated rows, and whether the denominator should include untagged orders.)
- What if `region` arrived as 'eu' and 'EU ' alongside 'EU'? (Tests normalizing the key before grouping so one market is not split across several rows.)