Build Health

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

Problem

The platform team is building a CI health report for the all-hands that scores each repository in ci_builds by how often its builds pass. Compute that pass rate over every build a repo ran, not just the ones that ended in success or failure, and include a repository only once at least 13 of its builds have resolved into a success or a failure.

Score every repo by how often CI stays green.

Tables

ci_builds

Columns: build_id INTEGER, repo_name TEXT, branch TEXT, status TEXT, dur_secs INTEGER, trigger TEXT, built_at TEXT

ci_builds: 10 of 200 rows
build_idrepo_namebranchstatusdur_secstriggerbuilt_at
5047backend-apidevelopfailed34pull_request2026-02-02 01:13:00
5094infrafeature/authcanceled53schedule2026-03-03 02:26:00
5141ml-pipelinefix/login-bugrunning72manual2026-04-04 03:39:00
5188mobile-apprelease/v2.0queued91tag2026-05-05 04:52:00
5235data-platformhotfix/paymentsuccess110webhook2026-06-06 05:05:00
5282frontendfeature /spacesfailedNULLpush2026-07-07 06:18:00
5329backend-apimaincanceled148pull_request2026-08-08 07:31:00
5376infradeveloprunning167schedule2026-09-09 08:44:00
5423ml-pipelinefeature/authqueued186manual2026-01-10 09:57:00
5470mobile-appfix/login-bugsuccess205tag2026-02-11 10:10:00

Expected output

First 4 of 4 rows
repo_namesuccess_countfailed_counttotal_buildssuccess_rate
backend-api683417.647
data-platform863225
frontend683218.75
mobile-app863423.529

Worked solution and explanation

What this is really asking

status is an enum with more than two values. 'success' and 'failed' are the ones you report, but the rate is over COUNT(*), so canceled, running, and queued builds all count against the repo. The twist: the report only lists repos with enough *resolved* builds to trust the number, and that resolved count is a different measure from the denominator.


Break down the requirements

Step 1: Pivot status into columns

Two SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) expressions for the resolved counts plus a COUNT(*) for total_builds, all in one GROUP BY repo_name pass.

Step 2: Rate is over all builds

Divide successes by COUNT(*), not by success + failed. Canceled, running, and queued builds belong in the denominator. Scale by 100.0 first to force float division, then wrap the result in ROUND(..., 3).

Step 3: Gate on resolved volume

HAVING SUM(CASE WHEN status IN ('success','failed') THEN 1 ELSE 0 END) >= 13 keeps only repos with enough finished builds for the rate to mean anything. Notice this gate counts *resolved* builds while the rate's denominator counts *all* of them: two different measures living in one query.


The solution

CI SUCCESS RATE BY REPO
SELECT
  repo_name,
  SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) AS success_count,
  SUM(CASE WHEN status = 'failed'  THEN 1 ELSE 0 END) AS failed_count,
  COUNT(*) AS total_builds,
  ROUND(100.0 * SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) / COUNT(*), 3) AS success_rate
FROM ci_builds
GROUP BY repo_name
HAVING SUM(CASE WHEN status IN ('success', 'failed') THEN 1 ELSE 0 END) >= 13

COMMON FOLLOW-UP QUESTIONS

Common follow-up questions