Blast Radius

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
IBM

Problem

After a run of rollbacks, leadership wants to know how much deployment capacity each service is bleeding to failures. For every service, report the share of its finished deployments that failed, and the share of all the time it spent deploying, including deploys still in flight, that those failures consumed. List the services alphabetically.

When deploys fail, how bad is the blast radius?

Tables

deploy_logs

Columns: log_id INTEGER, svc_name TEXT, version TEXT, env_name TEXT, status TEXT, deploy_at TEXT, dur_secs INTEGER, author TEXT

deploy_logs: 10 of 200 rows
log_idsvc_nameversionenv_namestatusdeploy_atdur_secsauthor
131payment-apiv1.0.2stagingfailed2026-02-02 01:11:0023bob
162user-svcv1.1.0devrolled_back2026-03-03 02:22:0036charlie
193search-api2.0.0canaryin_progress2026-04-04 03:33:0049dana
224gatewayv2.1.0ProductionSuccess2026-05-05 04:44:0062eve
255notif-svc2.1.1STAGINGFAILED2026-06-06 05:55:0075frank
286analyticsv3.0.0-rc1productionsuccess2026-07-07 06:06:0088Alice
317ml-servingv1.0.3stagingfailed2026-08-08 07:17:00NULLBOB
348auth-svcv1.0.1devRolled_Back2026-09-09 08:28:00114alice
379Payment-APIv1.0.2canaryin_progress2026-01-10 09:39:00127bob
410user-svcv1.1.0ProductionSuccess2026-02-11 10:50:00140charlie

Expected output

First 5 of 11 rows
svc_namefailure_pctfailure_time_pct
payment-api100100
Payment-APINULL0
analytics33.3338.9
gateway30.7754.04
user-svc38.4625.99

Worked solution and explanation

What this really is

Strip the incident-review costume and this is two conditional percentages hiding in one table: what share of a service's finished deploys failed, and what share of its deploy-seconds those failures burned. Anyone can filter for failures. The tell is spotting that both numbers are conditional SUMs over the same GROUP BY, so the whole thing collapses into a single scan instead of two queries. Two quieter traps live in the data. First, status arrives as 'FAILED', 'failed', and 'Success' all at once, and 'rolled_back' counts as a failure even though the word 'failed' never appears in it; miss the case-fold or the synonym and your failure counts silently under-report. Second, the two percentages do not share a denominator. The failure RATE is about outcomes, so it runs over finished deploys only; an in_progress deploy has no outcome yet and would dilute the rate if you left it in. The TIME share is about consumed capacity, and an in_progress deploy is still burning deploy-seconds right now, so its elapsed time stays in the time denominator. That split is exactly why you cannot just filter in_progress out with a WHERE: you need it gone from the count but present in the time total.


Break down the requirements

Step 1: Classify each deploy for one service at a time

For each svc_name, a deployment is a failure when LOWER(status) is 'failed' or the synonym 'rolled_back' (the prose's run of rollbacks). A deploy still in_progress has no outcome yet, so it is neither a failure nor part of the finished-deploy count, but it has still consumed deployment time.

Step 2: Compute both percentages in one pass

Count share = 100.0 * failed-deploy count / count of FINISHED deploys. COUNT(NULLIF(LOWER(status), 'in_progress')) turns each in_progress row into NULL, and COUNT skips NULLs, so only completed deploys land in that denominator. The time share swaps the counted 1 for dur_secs in the numerator, over SUM(dur_secs) across every row in the group, in_progress included, because those deploys are still consuming capacity so their elapsed time belongs in the total. That is why you reach for NULLIF instead of a WHERE filter: a WHERE that dropped in_progress would also strip its time from the denominator and inflate every failure-time share.


The solution

Dual failure percentage computation
SELECT
    svc_name,
    ROUND(100.0 * SUM(CASE WHEN LOWER(status) IN ('failed', 'rolled_back') THEN 1 ELSE 0 END) / COUNT(NULLIF(LOWER(status), 'in_progress')), 2) AS failure_pct,
    ROUND(100.0 * SUM(CASE WHEN LOWER(status) IN ('failed', 'rolled_back') THEN dur_secs ELSE 0 END) / SUM(dur_secs), 2) AS failure_time_pct
FROM deploy_logs
GROUP BY svc_name
ORDER BY svc_name

Common follow-up questions