Zero-Retry Job Ratio by Priority
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
- City and County of San Francisco
Problem
What share of each job status in batch_jobs ran with zero retries, out of every job carrying that status? The status column is written in inconsistent letter case, so 'FAILED' and 'failed' count as one outcome.
No retries needed. First try success rate.
Tables
batch_jobs
Columns: job_id INTEGER, job_name TEXT, status TEXT, rows_done INTEGER, started TEXT, ended TEXT, priority INTEGER, retries INTEGER
| job_id | job_name | status | rows_done | started | ended | priority | retries |
|---|---|---|---|---|---|---|---|
| 1047 | user_export | running | 97 | 2026-02-02 01:00:00 | 2026-02-02 03:11:00 | 3 | 0 |
| 1094 | data_cleanup | failed | 194 | 2026-03-03 02:00:00 | 2026-03-03 04:22:00 | 6 | 0 |
| 1141 | email_blast | queued | 291 | 2026-04-04 03:00:00 | 2026-04-04 05:33:00 | 9 | 0 |
| 1188 | index_rebuild | canceled | 388 | 2026-05-05 04:00:00 | NULL | 2 | 0 |
| 1235 | cache_warm | Completed | 485 | 2026-06-06 05:00:00 | 2026-06-06 07:55:00 | 5 | 0 |
| 1282 | log_archive | FAILED | NULL | 2026-07-07 06:00:00 | 2026-07-07 08:06:00 | 8 | 0 |
| 1329 | metric_agg | completed | 679 | 2026-08-08 07:00:00 | 2026-08-08 09:17:00 | 1 | 0 |
| 1376 | backup_db | running | 776 | 2026-09-09 08:00:00 | NULL | 4 | 0 |
| 1423 | sync_elastic | failed | 873 | 2026-01-10 09:00:00 | 2026-01-10 11:39:00 | 7 | 5 |
| 1470 | daily_report | queued | 970 | 2026-02-11 10:00:00 | 2026-02-11 12:50:00 | 0 | 0 |
Expected output
| job_status | zero_retry_jobs | total_jobs | zero_retry_share |
|---|---|---|---|
| canceled | 24 | 28 | 0.8571428571428571 |
| completed | 52 | 56 | 0.9285714285714286 |
| failed | 50 | 58 | 0.8620689655172413 |
| queued | 26 | 28 | 0.9285714285714286 |
| running | 26 | 30 | 0.8666666666666667 |
Worked solution and explanation
What this really is
This is a subset-over-whole ratio dressed up as a reliability report. Everyone can count zero-retry jobs, and everyone can count all jobs. What separates candidates is whether both counts come out of the same unfiltered scan of batch_jobs. Reach for WHERE retries = 0 and the denominator is gone: every status reports a clean share of exactly 1. Survive that and integer division is waiting next, turning 26 out of 30 into 0 so every status looks equally broken.
There is a third, quieter trap in the data: status holds 'completed' and 'Completed', 'failed' and 'FAILED'. Group on the raw column and one outcome splits into two rows with two different shares, and neither is the real one.
Step 1: Normalize the outcome before grouping
Group on LOWER(status), not status. Seven raw spellings collapse to five outcomes; 'failed' goes from two half-sized groups to one group of 58 jobs, which is the denominator the share actually needs.
Step 2: Count the subset inside the group
SUM(CASE WHEN retries = 0 THEN 1 ELSE 0 END) counts the clean runs while COUNT(*) counts everything, side by side in one pass. No filter touches the rows, so both numbers describe the same population.
Step 3: Divide as decimals
Both counts are integers, so multiply the clean-run count by 1.0 before dividing by COUNT(*) to force decimal division. The CASE sum appears twice, once as the reported count and once in the ratio, but it is the same aggregate over the same group, so it costs nothing extra.
SELECT
LOWER(status) AS job_status,
SUM(CASE WHEN retries = 0 THEN 1 ELSE 0 END) AS zero_retry_jobs,
COUNT(*) AS total_jobs,
SUM(CASE WHEN retries = 0 THEN 1 ELSE 0 END) * 1.0 / COUNT(*) AS zero_retry_share
FROM batch_jobs
GROUP BY LOWER(status)- Filter first
WHERE retries = 0thenGROUP BYleaves only clean jobs, soCOUNT(*)equals the zero-retry count and every share is 1. Getting the total back means a second query and a join.- Count conditionally
SUM(CASE WHEN retries = 0 ...)next toCOUNT(*)keeps every row in the group, so 'canceled' honestly reports 24 clean out of 28.
Common follow-up questions
- How would you also report the average retry count per status? (Add `AVG(retries)` to the same select list; no second pass needed.)
- Which statuses have fewer than 87% clean runs? (Filter with `HAVING` on the ratio expression.)
- What if `retries` could be `NULL` for jobs that never started? (`NULL = 0` is not true, so those rows count toward `total_jobs` only; decide whether `COALESCE(retries, 0)` or excluding them matches the business meaning.)