Against the Clock
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
- L5
- Asked in
- Instacart
Problem
The on-call team's job report keeps breaking on batch_jobs rows that violate its two rules: every job should have an ended time by now, and no job should end before it started. List every job that breaks either rule with its job_id, job_name and runtime in whole minutes from started to ended.
Promised by noon. Delivered at midnight.
Tables
batch_jobs
Columns: job_id INTEGER, job_name TEXT, started TEXT, ended TEXT, status TEXT, rows_done INTEGER, 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_id | job_name | minutes_elapsed |
|---|---|---|
| 1188 | index_rebuild | NULL |
| 1376 | backup_db | NULL |
| 1564 | data_cleanup | NULL |
| 1752 | log_archive | NULL |
| 2034 | data_cleanup | -1317.9999998956919 |
Worked solution and explanation
What this really tests
This is a constraint audit dressed up as a broken runtime report. The job table promises two things: every job carries an ended time, and that time never precedes started. The skill is finding the rows that break either promise and reporting their runtime. The trap is believing one test covers both. Filter on minutes_elapsed < 0 and you catch the jobs that ended before they started, but a job with no ended has a runtime of NULL, NULL is never less than zero, and all 50 stuck jobs silently drop out of the audit.
Two rules, two tests
Step 1: Test the missing end directly
ended IS NULL is the only way to ask whether a value is absent. ended = NULL is never true, and ended = '' compares against empty text the table never stores. Do not excuse 'running' or 'queued' rows by status: the report treats every job as overdue for an end time, and status does not line up with ended here anyway (some 'running' rows carry one).
Step 2: Compare the times as they are stored
started and ended are fixed-width 'yyyy-MM-dd HH:mm:ss' strings, so text order is time order and ended < started flags the end-before-start rows without converting anything. Join the two tests with OR: a row only has to break one rule to be reported.
Step 3: Convert before you subtract
Ordering survives as text; arithmetic does not. A lenient engine reads each string as its leading number, the year, so ended - started comes out 0. Cast both to TIMESTAMP, subtract to get an interval, take EXTRACT(EPOCH FROM ...) for seconds and divide by 60. A job stamped as starting at 22:00 and ending at 00:02 on the same date reports -1318.
The solution
SELECT job_id,
job_name,
EXTRACT(EPOCH FROM CAST(ended AS TIMESTAMP) - CAST(started AS TIMESTAMP)) / 60 AS minutes_elapsed
FROM batch_jobs
WHERE ended IS NULL
OR ended < startedSELECT job_id,
job_name,
EXTRACT(EPOCH FROM CAST(ended AS TIMESTAMP) - CAST(started AS TIMESTAMP)) / 60 AS minutes_elapsed
FROM batch_jobs
WHERE EXTRACT(EPOCH FROM CAST(ended AS TIMESTAMP) - CAST(started AS TIMESTAMP)) < 0Returns only the end-before-start jobs; every job with no end is missed.
Common follow-up questions
- How would you add a column saying which rule each job broke? (Tests labeling each violation rather than only listing offenders.)
- If running jobs were allowed to have no end, how would the missing-end rule change given how `status` is spelled? (Tests scoping a rule by a column with mixed casing.)
- Every end-before-start job started at 22:00 or later. What would you suspect about how `ended` is recorded, and how would you repair those runtimes? (Tests reasoning about the cause of a constraint violation.)