10 Lowest Uptime Services
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
Problem
The SRE team is preparing a reliability review for the quarterly infrastructure meeting. Each service has multiple health check records; surface the 10 least reliable, judged by their lowest recorded uptime, and if several services are tied for that 10th spot include all of them. List each service with its lowest uptime, weakest first.
Ten services at the bottom of the reliability chart.
Tables
svc_health
Columns: check_id INTEGER, svc_name TEXT, status TEXT, latency REAL, uptime REAL, checked TEXT, region TEXT
| check_id | svc_name | status | latency | uptime | checked | region |
|---|---|---|---|---|---|---|
| 137 | payment-api | degraded | 3.6 | 97.03 | 2026-02-02 01:05:00 | us-west-2 |
| 174 | user-svc | unhealthy | 6.7 | 94.06 | 2026-03-03 02:10:00 | eu-west-1 |
| 211 | search-api | timeout | 9.8 | 91.09 | 2026-04-04 03:15:00 | ap-south-1 |
| 248 | gateway | Healthy | 12.9 | 98.12 | 2026-05-05 04:20:00 | eu-central-1 |
| 285 | notif-svc | DEGRADED | 16 | 95.15 | 2026-06-06 05:25:00 | us-east-1 |
| 322 | ml-serving | healthy | 19.1 | 92.18 | 2026-07-07 06:30:00 | us-west-2 |
| 359 | cache-svc | degraded | NULL | 99.21 | 2026-08-08 07:35:00 | eu-west-1 |
| 396 | queue-worker | unhealthy | 25.3 | 96.24 | 2026-09-09 08:40:00 | ap-south-1 |
| 433 | cron-svc | timeout | 28.4 | 93.27 | 2026-01-10 09:45:00 | eu-central-1 |
| 470 | auth-svc | Healthy | 31.5 | 90.3 | 2026-02-11 10:50:00 | us-east-1 |
Expected output
| svc_name | min_uptime |
|---|---|
| payment-api | 88 |
| notif-svc | 88.2 |
| cron-svc | 88.4 |
| search-api | 88.6 |
| queue-worker | 89.35 |
Worked solution and explanation
Underneath the reliability review, this is a per-service floor followed by a cutoff drawn on values, not rows. Everyone finds MIN(uptime). What separates candidates is the order of operations and where the line falls. Sort the raw svc_health rows and take ten, and you are listing checks: 'payment-api' and 'search-api' each show up twice, and half the worst services never appear. Collapse to services correctly but cut with LIMIT 10, and a service tied at the tenth-worst uptime is kept or dropped by whatever order the engine happened to emit. The review then silently misses a failing service.
Build it in three moves
Step 1: Collapse the checks to one floor per service
GROUP BY svc_name with MIN(uptime) turns every check into one number per service: its worst reading. This has to come first because the cutoff is about services. MIN also skips the 15 checks that never recorded an uptime, which is exactly right: a missing reading says nothing about how low a service dipped.
Step 2: Number the floors with DENSE_RANK()
DENSE_RANK() OVER (ORDER BY MIN(uptime) ASC) gives equal floors the same number, so the filter keeps every service sitting on the tenth value. It can share a SELECT with the GROUP BY because windows run after grouping: the window sees one row per service.
Step 3: Cut at 10 and list weakest first
Filter rnk <= 10 in the outer query, because a window result cannot be filtered in the WHERE of the query that computes it. Then sort by min_uptime ascending. On this data the cut lands cleanly: 'gateway' is tenth at 91.65, and five newer services share 95.0 just past it. Move the cutoff to 11 and all five arrive together, which is the case the rule exists for.
The solution
SELECT svc_name, min_uptime
FROM (
SELECT
svc_name,
MIN(uptime) AS min_uptime,
DENSE_RANK() OVER (ORDER BY MIN(uptime) ASC) AS rnk
FROM svc_health
GROUP BY svc_name
) ranked
WHERE rnk <= 10
ORDER BY min_uptime ASCSELECT svc_name, uptime
FROM svc_health
ORDER BY uptime
LIMIT 10Returns check rows: 'payment-api' twice, and engines that sort NULLs low lead with the checks that have no uptime at all.
- `LIMIT 10` on the floors
- Stops at exactly ten rows. If three services share the tenth-worst floor, two of them vanish, and which two depends on the engine's sort, so reruns can disagree.
- `rnk <= 10` on `DENSE_RANK()`
- Stops at the tenth floor value. Every service sharing it comes along, and the answer is the same on every run.
Common follow-up questions
- What if the review used each service's average uptime instead of its lowest? (Swapping the aggregate leaves the cutoff logic untouched.)
- The meeting insists on exactly ten rows: how do you break ties at the cutoff by `svc_name`? (Turns the tie rule into a tiebreak: `ROW_NUMBER()` ordered by the floor, then the name.)
- What changes if you need the ten worst services per `region`? (Adds `PARTITION BY region` to the window and moves `region` into the grouping.)
- Could you solve this without a window function? (A correlated count of services with a lower floor works and shows you understand what the rank means.)