Until Relieved

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
mid
Asked in
NVIDIA

Problem

We're auditing our release cadence, where each successful production deploy of a service stays live until the next successful production deploy of that same service replaces it. The environment and status labels were recorded with inconsistent casing over the years, so match them case-insensitively. For every release that was eventually replaced, report the service, the version, and how many calendar days it stayed live, longest-lived first; when two releases held for the same number of days, list them alphabetically by service and then the earlier deploy first.

Every deploy stands its post until the next one arrives. Find the ones that stood longest.

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 62 rows
svc_nameversiondays_live
analyticsv3.0.0-rc1369
analyticsv3.0.0-rc1369
auth-svcv1.0.1369
gatewayv2.1.0369
user-svcv1.1.0369

Worked solution and explanation

What this problem really is

This is a per-partition time-gap problem wearing a DevOps costume. The real question: for each service, how long did each release live before the next one replaced it? That is a LEAD over a service-partitioned timeline, then a date subtraction. Anyone can filter to production. Three things separate candidates here: handling the case-inconsistent env_name and status cleanly before you filter, counting whole calendar days instead of letting the time of day leak into a fractional answer, and recognizing that the most recent release of each service has no successor, so its lifespan is undefined, not zero. Hard-code one casing and you silently drop every 'Production' and 'Success' row, inflating every surviving tenure; subtract raw timestamps and two releases that both spanned 369 dates come back as 369 and 368 depending on the hour they shipped; keep the last release and you invent a NULL-length tenure that sorts wrong.


Break down the requirements

Step 1: Normalize casing, then filter to prod successes

env_name arrives as 'Production', 'production' and status as 'Success', 'success'. Compare on LOWER(...) so all casings survive. A raw env_name = 'production' quietly discards the 'Production' rows, which merges away intermediate deploys and stretches every tenure.

Step 2: Order each service's timeline

PARTITION BY svc_name ORDER BY deploy_at gives each service its own chronological sequence of live releases. The partition is what stops one service's next deploy from being attributed to another.

Step 3: Look ahead to the replacement, count whole days

LEAD(deploy_at) pulls the timestamp of the next deploy for the same service. Subtract on the date portions, julianday(date(next_deploy_at)) minus julianday(date(deploy_at)), so the gap returns as whole calendar days rather than a fraction skewed by the clock time each deploy happened to run. Subtracting raw timestamps is where the 369-vs-368 wobble comes from.

Step 4: Drop the still-live release and sort deterministically

The latest deploy per service has no LEAD value (NULL), meaning it is still live and its tenure is not yet known. Filter next_deploy_at IS NOT NULL, then order by days_live descending. Ties are common because many releases share a lifespan, so break them the same way every run: alphabetically by svc_name, then earliest deploy first, or the row order wobbles between executions.


The solution

Release tenure via LEAD
SELECT
  svc_name,
  version,
  CAST(julianday(date(next_deploy_at)) - julianday(date(deploy_at)) AS INTEGER) AS days_live
FROM (
  SELECT
    svc_name,
    version,
    deploy_at,
    LEAD(deploy_at) OVER (PARTITION BY svc_name ORDER BY deploy_at) AS next_deploy_at
  FROM (
    SELECT svc_name, version, deploy_at
    FROM deploy_logs
    WHERE LOWER(env_name) = 'production' AND LOWER(status) = 'success'
  ) prod_deploys
) lifespans
WHERE next_deploy_at IS NOT NULL
ORDER BY days_live DESC, svc_name, deploy_at

Common follow-up questions