Successful Build Duration by Repository
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
- Asana
Problem
List how many seconds each repository's successful builds ran in total during January 2026, reading the ci_builds log. We want every repository in that table on the list, with a total of zero for any that has nothing to add up that month.
CI throughput, repo by repo.
Tables
ci_builds
Columns: build_id INTEGER, repo_name TEXT, branch TEXT, status TEXT, dur_secs INTEGER, trigger TEXT, built_at TEXT
| build_id | repo_name | branch | status | dur_secs | trigger | built_at |
|---|---|---|---|---|---|---|
| 5047 | backend-api | develop | failed | 34 | pull_request | 2026-02-02 01:13:00 |
| 5094 | infra | feature/auth | canceled | 53 | schedule | 2026-03-03 02:26:00 |
| 5141 | ml-pipeline | fix/login-bug | running | 72 | manual | 2026-04-04 03:39:00 |
| 5188 | mobile-app | release/v2.0 | queued | 91 | tag | 2026-05-05 04:52:00 |
| 5235 | data-platform | hotfix/payment | success | 110 | webhook | 2026-06-06 05:05:00 |
| 5282 | frontend | feature /spaces | failed | NULL | push | 2026-07-07 06:18:00 |
| 5329 | backend-api | main | canceled | 148 | pull_request | 2026-08-08 07:31:00 |
| 5376 | infra | develop | running | 167 | schedule | 2026-09-09 08:44:00 |
| 5423 | ml-pipeline | feature/auth | queued | 186 | manual | 2026-01-10 09:57:00 |
| 5470 | mobile-app | fix/login-bug | success | 205 | tag | 2026-02-11 10:10:00 |
Expected output
| repo_name | total_dur_secs |
|---|---|
| backend-api | 160 |
| data-platform | 0 |
| frontend | 0 |
| ml-pipeline | 870 |
| mobile-app | 320 |
Worked solution and explanation
This is an outer-join roster problem dressed up as a CI cost report. Everyone writes the sum. What separates candidates is where the success and January conditions live. Put them in WHERE and they run after the repositories are already gone. On this seed that query returns four rows: 'data-platform' and 'infra' vanish because neither had a successful January build, and 'frontend' comes back NULL because its only January success has no recorded dur_secs. The answer is all six repositories, three of them at zero.
Why the obvious query comes up short
SELECT repo_name,
SUM(dur_secs) AS total_dur_secs
FROM ci_builds
WHERE status = 'success'
AND built_at BETWEEN '2026-01-01 00:00:00' AND '2026-01-31 23:59:59'
GROUP BY repo_nameFour rows: 'backend-api' 160, 'frontend' NULL, 'ml-pipeline' 870, 'mobile-app' 320. Two repositories never reach GROUP BY.
Step 1: Build the roster before you filter anything
SELECT DISTINCT repo_name FROM ci_builds yields the six repositories regardless of status or month, and that is the list the output owes. The DISTINCT is load-bearing: each repository sits on about 33 rows, so without it every matched build is joined and summed once per copy.
Step 2: Attach only January successes, in the ON clause
LEFT JOIN the roster back to ci_builds and put the repository match, status = 'success' and the date range in ON. A repository with no matching build still survives, with NULL build columns. built_at carries a time, so the upper bound is '2026-01-31 23:59:59': ending at '2026-01-31' would stop at midnight and lose the last day.
Step 3: Default the empty sum to zero
SUM over nothing but NULLs is NULL. 'data-platform' and 'infra' joined no build. 'frontend' joined one build whose dur_secs is NULL. COALESCE(SUM(cb.dur_secs), 0) turns all three into the zero the report promises.
SELECT repos.repo_name,
COALESCE(SUM(cb.dur_secs), 0) AS total_dur_secs
FROM (SELECT DISTINCT repo_name FROM ci_builds) AS repos
LEFT JOIN ci_builds AS cb
ON cb.repo_name = repos.repo_name
AND cb.status = 'success'
AND cb.built_at BETWEEN '2026-01-01 00:00:00' AND '2026-01-31 23:59:59'
GROUP BY repos.repo_nameCommon follow-up questions
- If you used `SUM(CASE WHEN status = 'success' THEN dur_secs END)` grouped over all of `ci_builds` instead of a join, which repositories come back `NULL`, and why is that version a single scan? (Tests that the conditional form keeps every group by construction but still needs the zero default.)
- How would you restrict to one calendar month when `built_at` is stored as TEXT in mixed formats? (Tests awareness that string comparison only works on a consistent, zero-padded format.)
- If two builds for the same repository overlap in time, does summing `dur_secs` overstate the wall-clock time the repository kept a runner busy? (Tests the difference between summed work and elapsed time for parallel builds.)