Deploy Cadence
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
- L3
Problem
From the deploy_logs table, report each environment's number of deployments, its average deployment duration in seconds, and how many unique services have been deployed there, listed from the most deployments to the fewest. The logs spell environment and service names inconsistently, so names that differ only in letter case or surrounding spaces count as the same environment or service.
Which environments ship the most?
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
| log_id | svc_name | version | env_name | status | deploy_at | dur_secs | author |
|---|---|---|---|---|---|---|---|
| 131 | payment-api | v1.0.2 | staging | failed | 2026-02-02 01:11:00 | 23 | bob |
| 162 | user-svc | v1.1.0 | dev | rolled_back | 2026-03-03 02:22:00 | 36 | charlie |
| 193 | search-api | 2.0.0 | canary | in_progress | 2026-04-04 03:33:00 | 49 | dana |
| 224 | gateway | v2.1.0 | Production | Success | 2026-05-05 04:44:00 | 62 | eve |
| 255 | notif-svc | 2.1.1 | STAGING | FAILED | 2026-06-06 05:55:00 | 75 | frank |
| 286 | analytics | v3.0.0-rc1 | production | success | 2026-07-07 06:06:00 | 88 | Alice |
| 317 | ml-serving | v1.0.3 | staging | failed | 2026-08-08 07:17:00 | NULL | BOB |
| 348 | auth-svc | v1.0.1 | dev | Rolled_Back | 2026-09-09 08:28:00 | 114 | alice |
| 379 | Payment-API | v1.0.2 | canary | in_progress | 2026-01-10 09:39:00 | 127 | bob |
| 410 | user-svc | v1.1.0 | Production | Success | 2026-02-11 10:50:00 | 140 | charlie |
Expected output
| env_name | deploy_count | avg_duration | unique_services |
|---|---|---|---|
| staging | 66 | 283.64285714285717 | 4 |
| production | 66 | 278.55172413793105 | 4 |
| dev | 34 | 343.2857142857143 | 4 |
| canary | 34 | 288.6 | 4 |
Worked solution and explanation
What this problem is really about
This is a three-measure environment summary with a data-cleaning problem hiding in the keys. The aggregates are the easy part: everyone writes COUNT(*), AVG(dur_secs) and a unique-service count over one grouping. What separates candidates is noticing that the log spells the same things several ways: 'production' and 'Production', 'staging' and 'STAGING', 'dev' and 'Dev', and one service as 'payment-api', 'Payment-API', ' payment-api' and 'payment-api '. Group on the raw env_name and you hand back seven environments where four exist, production's 66 deploys split 34 and 32, and a stray 'Dev' row with one deploy and no average. Count raw svc_name values and canary claims six services when it ran four.
Walking through it
Step 1: Clean the environment key before grouping
GROUP BY LOWER(env_name) folds the three case pairs into four environments. env_name has no padding, so case is the only fix it needs. Select the same LOWER(env_name) so the output label is exactly the group you formed.
Step 2: Count each service once, under one spelling
COUNT(DISTINCT LOWER(TRIM(svc_name))). DISTINCT turns a deploy tally into a service count, TRIM removes the stray spaces on ' payment-api' and 'payment-api ', and LOWER folds 'Payment-API'. Drop any one of the three and canary or staging gains a phantom service.
Step 3: Let the average skip missing durations
28 of the 200 deploys never logged dur_secs. AVG(dur_secs) divides by the non-NULL rows only, so dev reads 343.29. Hand-rolling SUM(dur_secs) / COUNT(*) divides by all 34 dev deploys and reports 282.71.
Step 4: Sort by deployment count, highest first
ORDER BY deploy_count DESC. Production and staging tie at 66 and canary and dev at 34; the question asks only for most deployments first, so either order inside a tie is correct.
The solution
SELECT
LOWER(env_name) AS env_name,
COUNT(*) AS deploy_count,
AVG(dur_secs) AS avg_duration,
COUNT(DISTINCT LOWER(TRIM(svc_name))) AS unique_services
FROM deploy_logs
GROUP BY LOWER(env_name)
ORDER BY deploy_count DESC- Raw keys
GROUP BY env_namewithCOUNT(DISTINCT svc_name): seven rows, 'Production' at 34 and 'production' at 32, canary at 6 services, 'STAGING' at 5, and a 'Dev' row with one deploy and a NULL average.- Cleaned keys
GROUP BY LOWER(env_name)withCOUNT(DISTINCT LOWER(TRIM(svc_name))): four rows, production and staging at 66 deploys each, canary and dev at 34, and every environment running 4 services.
Common follow-up questions
- How would you add the most recent deploy per environment? (`MAX(deploy_at)` in the same pass.)
- How would you show the share of each environment's deploys that failed? (A conditional count over `status`, which is itself mixed-case ('failed', 'FAILED').)
- What if you needed monthly trends per environment? (Add a month bucket derived from `deploy_at` to the grouping key.)