Extremely Late Resolutions
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
- General Assembly
Problem
What were the first three alerts each service fired, according to alert_events, and where does each one fall in its service's history? The on-call review team wants those alerts exactly as they were logged, every column in its original spelling, with the lower alert_id counting as earlier when two fired at the same moment.
Twenty minutes past the SLA. Still unresolved.
Tables
alert_events
Columns: alert_id INTEGER, svc_name TEXT, severity TEXT, status TEXT, fired_at TEXT, ack_by TEXT, resolved TEXT
| alert_id | svc_name | severity | status | fired_at | ack_by | resolved |
|---|---|---|---|---|---|---|
| 129 | payment-api | high | acknowledged | 2026-02-02 01:07:00 | bob | 2026-02-02 03:11:00 |
| 158 | user-svc | medium | resolved | 2026-03-03 02:14:00 | charlie | 2026-03-03 04:22:00 |
| 187 | search-api | low | silenced | 2026-04-04 03:21:00 | dana | NULL |
| 216 | gateway | Critical | firing | 2026-05-05 04:28:00 | NULL | 2026-05-05 06:44:00 |
| 245 | notif-svc | HIGH | acknowledged | 2026-06-06 05:35:00 | alice | 2026-06-06 07:55:00 |
| 274 | db-primary | critical | resolved | 2026-07-07 06:42:00 | bob | NULL |
| 303 | cache-01 | high | silenced | 2026-08-08 07:49:00 | charlie | 2026-08-08 09:17:00 |
| 332 | auth-svc | medium | firing | 2026-09-09 08:56:00 | NULL | 2026-09-09 10:28:00 |
| 361 | payment-api | low | acknowledged | 2026-01-10 09:03:00 | eve | NULL |
| 390 | user-svc | Critical | resolved | 2026-02-11 10:10:00 | alice | 2026-02-11 12:50:00 |
Expected output
| alert_id | svc_name | severity | status | fired_at | ack_by | resolved | rnk |
|---|---|---|---|---|---|---|---|
| 10003016 | auth-svc | Critical | firing | 2022-04-17 16:52:00 | NULL | 2022-04-17 18:56:00 | 1 |
| 10003056 | auth-svc | medium | firing | 2022-08-01 08:32:00 | NULL | 2022-08-01 10:16:00 | 2 |
| 10003031 | cache-01 | high | silenced | 2022-07-04 07:37:00 | bob | 2022-07-04 09:41:00 | 1 |
| 10003086 | db-primary | medium | resolved | 2022-02-03 14:02:00 | bob | 2022-02-03 16:46:00 | 1 |
| 10003061 | notif-svc | high | acknowledged | 2022-01-06 13:07:00 | bob | 2022-01-06 15:11:00 | 1 |
Worked solution and explanation
What this really is
This is top-N-per-group dressed up as an on-call history review. Everyone sees 'first three' and types ORDER BY fired_at LIMIT 3, and that is the trap: LIMIT caps the whole result, so you get three alerts from whichever service fired first and nothing for the other services. The candidates who dodge that often swing to MIN(fired_at), which only ever finds the first alert. The skill being probed is whether you can number rows inside each service, keep the whole row, and hand back its position.
- Limit the whole table
ORDER BY fired_at LIMIT 3sorts every alert together and stops after three rows total. AMIN(fired_at)join-back or a single-row dedup does better on coverage but still returns one alert per service and no position.- Number inside each service
ROW_NUMBER() OVER (PARTITION BY svc_name ORDER BY fired_at, alert_id)restarts at 1 for every service. Keeprnk <= 3and each service contributes its own three full rows, labeled 1, 2, 3.
Building it
Step 1: Partition by svc_name
PARTITION BY svc_name makes the count restart for every service. That is the per-service boundary LIMIT has no way to express: it only knows the total result.
Step 2: Order by fired_at, then alert_id
Order each partition by fired_at, then alert_id. Without the second key, two alerts fired in the same minute trade places run to run, and which one is 'second' becomes a coin flip the grader will not forgive.
Step 3: Keep rnk <= 3 in the outer query
A window alias cannot be filtered in the SELECT that computes it, so the numbering lives in the derived table ranked_alerts and the outer query keeps rnk <= 3. There is no filter on resolved and no cleanup of severity: every alert comes back as it was logged and holds its place in line.
SELECT alert_id, svc_name, severity, status, fired_at, ack_by, resolved, rnk
FROM (
SELECT alert_id,
svc_name,
severity,
status,
fired_at,
ack_by,
resolved,
ROW_NUMBER() OVER (PARTITION BY svc_name ORDER BY fired_at, alert_id) AS rnk
FROM alert_events
) AS ranked_alerts
WHERE rnk <= 3Common follow-up questions
- Now return only each service's second alert. What changes? (Tests whether the candidate sees the filter, not the window, changes.)
- Only alerts with `severity` 'critical' should count, but casing varies ('Critical', 'critical'). Does that filter go inside or outside `ranked_alerts`, and why does it matter? (Tests where a row filter sits relative to the numbering.)
- `fired_at` is TEXT. When does sorting it as a string stop matching chronological order? (Tests reasoning about `fired_at` stored as TEXT.)
- New alerts land every minute. Do the first three alerts per service ever change once set, and how would you exploit that? (Tests incremental thinking at scale.)