Loudest in the Room
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
- L4
- Asked in
- DoorDash
Problem
Our daily busiest-endpoints panel no longer matches what on-call sees in api_calls, partly because some endpoint paths were logged with stray spaces around them and show up as two different endpoints. For every day, return the endpoints whose call count is among that day's three highest counts, with the day, the cleaned endpoint, and its level (1 for the busiest count, 3 for the third highest).
Every day, a few endpoints carry the load. Surface them.
Tables
api_calls
Columns: call_id INTEGER, endpoint TEXT, method TEXT, status INTEGER, latency REAL, user_id INTEGER, call_time TEXT, err_msg TEXT
| call_id | endpoint | method | status | latency | user_id | call_time | err_msg |
|---|---|---|---|---|---|---|---|
| 8079 | /api/v1/orders | POST | 200 | 4.2 | 100 | 2026-02-02 01:07:00 | NULL |
| 8158 | /api/v2/products | PUT | 200 | 7.9 | 197 | 2026-03-03 02:14:00 | NULL |
| 8237 | /api/v1/search | DELETE | 201 | 11.6 | 294 | 2026-04-04 03:21:00 | NULL |
| 8316 | /api/v1/auth/login | PATCH | 204 | 15.3 | 391 | 2026-05-05 04:28:00 | NULL |
| 8395 | /api/v1/auth/logout | get | 301 | 19 | NULL | 2026-06-06 05:35:00 | NULL |
| 8474 | /api/v2/analytics | post | 400 | 22.7 | 585 | 2026-07-07 06:42:00 | Not found |
| 8553 | /api/v1/payments | GET | 401 | 26.4 | 682 | 2026-08-08 07:49:00 | Unauthorized |
| 8632 | /api/v1/users/ | POST | 403 | 30.1 | 779 | 2026-09-09 08:56:00 | Rate limit exceeded |
| 8711 | /api/v2/products/ | PUT | 404 | 33.8 | 876 | 2026-01-10 09:03:00 | Internal server error |
| 8790 | /api/v1/users | DELETE | 500 | 37.5 | NULL | 2026-02-11 10:10:00 | Bad gateway |
Expected output
| call_day | endpoint | rnk |
|---|---|---|
| 2023-01-01 | /api/v1/users | 1 |
| 2023-01-12 | /api/v1/auth/logout | 1 |
| 2026-02-01 | /api/v1/search | 2 |
| 2026-02-01 | /api/v1/auth/login | 3 |
| 2026-02-02 | /api/v1/users | 2 |
Worked solution and explanation
What this really is
Strip the ops-dashboard costume and this is top-N-per-group, with the twist that trips people: N counts count-levels, not rows. You clean the endpoint path, count calls per day and endpoint, order the endpoints within a day by that count, and keep the three highest counts. Two decisions settle whether you pass: which ranking function you reach for, and where you put the level filter. Miss either and the query still runs, it just hands back the wrong set.
The traps
The build
Step 1: Count calls per day and cleaned endpoint
In daily_counts, bucket call_time to its calendar date with DATE(call_time), strip the path with TRIM(endpoint), and COUNT(*) grouped by both. Grouping on the raw timestamp would split each day into per-second fragments; grouping on the raw path would split padded endpoints in two.
Step 2: Assign a level within each day
In ranked, apply DENSE_RANK() OVER (PARTITION BY call_day ORDER BY call_count DESC). Partitioning by day restarts the numbering every day, descending count puts the busiest endpoint at level 1, and DENSE_RANK makes equal counts share a level with no gaps, so level 3 is the third-highest count.
Step 3: Filter to the three highest counts outside the window
In the outer query keep rows where rnk <= 3 and return the day, the endpoint and the level. Because equal counts share a level, a day can legitimately return more than three rows, and that is intended: it is exactly what a row cap would hide.
The solution
WITH daily_counts AS (
SELECT DATE(call_time) AS call_day,
TRIM(endpoint) AS endpoint,
COUNT(*) AS call_count
FROM api_calls
GROUP BY DATE(call_time), TRIM(endpoint)
),
ranked AS (
SELECT call_day,
endpoint,
DENSE_RANK() OVER (PARTITION BY call_day ORDER BY call_count DESC) AS rnk
FROM daily_counts
)
SELECT call_day, endpoint, rnk
FROM ranked
WHERE rnk <= 3Common follow-up questions
- The dashboard now wants exactly three rows per day even when there is a tie for third. What changes? (Switch to `ROW_NUMBER` and add a deterministic tiebreak column to the window's `ORDER BY` so the cut is reproducible.)
- Product wants the top three per day and region. How do you extend it? (Add `region` to both the `GROUP BY` and the `PARTITION BY` so the numbering restarts per day and region instead of per day.)
- Path hygiene keeps drifting. Where should the cleaning live long term? (Normalize on write so every reader agrees, or extend the cleaning (case, trailing slash) once product rules those are the same route.)