The Weight of a Verdict
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
- Asked in
- Zenefits
Problem
Each pipeline run in data_pipes gets benchmarked by the data platform team against every run sharing its status, using the total rows ingested across that status (a status whose runs never recorded an ingest count has no benchmark). Return every run with its original columns intact, alongside that status-wide total.
Every run carries the full measure of all who ended the same way.
Tables
data_pipes
Columns: pipe_id INTEGER, pipe_name TEXT, status TEXT, rows_in INTEGER, rows_out INTEGER, start_at TEXT, dur_secs INTEGER
| pipe_id | pipe_name | status | rows_in | rows_out | start_at | dur_secs |
|---|---|---|---|---|---|---|
| 131 | etl_users | failed | 137 | 97 | 2026-02-02 01:00:00 | 28 |
| 162 | etl_events | running | 274 | 194 | 2026-03-03 02:00:00 | 51 |
| 193 | sync_crm | queued | 411 | 291 | 2026-04-04 03:00:00 | 74 |
| 224 | agg_daily | skipped | 548 | 388 | 2026-05-05 04:00:00 | 97 |
| 255 | agg_weekly | Success | 685 | 485 | 2026-06-06 05:00:00 | NULL |
| 286 | export_s3 | FAILED | 822 | 582 | 2026-07-07 06:00:00 | 143 |
| 317 | import_csv | success | NULL | 679 | 2026-08-08 07:00:00 | 166 |
| 348 | ml_train | failed | 1096 | 776 | 2026-09-09 08:00:00 | 189 |
| 379 | dbt_build | running | 1233 | NULL | 2026-01-10 09:00:00 | 212 |
| 410 | etl_orders | queued | 1370 | 970 | 2026-02-11 10:00:00 | NULL |
Expected output
| pipe_id | pipe_name | status | rows_in | rows_out | start_at | dur_secs | status_total_rows_in |
|---|---|---|---|---|---|---|---|
| 286 | export_s3 | FAILED | 822 | 582 | 2026-07-07 06:00:00 | 143 | 197554 |
| 503 | sync_crm | FAILED | 1781 | 1261 | 2026-05-14 13:00:00 | 304 | 197554 |
| 255 | agg_weekly | Success | 685 | 485 | 2026-06-06 05:00:00 | NULL | 193718 |
| 131 | etl_users | failed | 137 | 97 | 2026-02-02 01:00:00 | 28 | 205500 |
| 193 | sync_crm | queued | 411 | 291 | 2026-04-04 03:00:00 | 74 | 186046 |
Worked solution and explanation
What this really tests
This is grain preservation dressed up as benchmarking. Totalling rows_in per status is the easy half. The real skill is attaching that total to every run without letting the status collapse the runs. Aggregate the table outright and 200 runs fold into seven status rows: the numbers are right, and every column the team asked to keep is gone.
Build it
Step 1: Read the grain off the ask
'Return every run with its original columns intact' fixes the output at one row per run. The benchmark belongs to the group, but it is reported at the run's grain, so it rides along as one extra column.
Step 2: Total rows_in over the run's whole status
SUM(rows_in) OVER (PARTITION BY status) adds up every run sharing the current row's status and writes that sum onto each of them. There is no ORDER BY inside the window, so the frame is the entire status, not a running prefix.
Step 3: Take status exactly as stored
The seed spells some statuses two ways, and each spelling is its own status: the preview shows 'FAILED' at 197554 and 'failed' at 205500. Partitioning on the raw value is what the grader expects.
Step 4: Let missing ingest counts fall out
SUM skips NULLs, so the 28 runs without a rows_in add nothing. Every one of them is a 'success' run, which leaves 'success' with no recorded counts at all: its benchmark comes back NULL, while 'Success' gets a real total. That is the empty benchmark the statement describes, not a bug.
SELECT
pipe_id,
pipe_name,
status,
rows_in,
rows_out,
start_at,
dur_secs,
SUM(rows_in) OVER (PARTITION BY status) AS status_total_rows_in
FROM data_pipesCommon follow-up questions
- What if the team wanted 'success' and 'Success' benchmarked as one status? (Partition by `LOWER(status)` while still returning the raw `status`; 'success' stops being empty because 'Success' brings counts.)
- How would you show 0 instead of an empty benchmark for a status with no ingest counts? (Wrap the window in `COALESCE(..., 0)`, and say why coalescing the result differs from treating each missing count as zero.)
- How would you add each run's share of its status total? (Divide `rows_in` by the same window, guarding the NULL total and avoiding integer division.)
- What if you needed a running total within each status by start time? (Add `ORDER BY start_at` to the window and decide how ties on `start_at` are framed (`ROWS` versus `RANGE`).)