Reviewer Performance Metrics
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
Problem
The status text in code_reviews can't be trusted for the platform team's review audit, because only a merge date proves a pull request actually shipped. For reviews opened since the start of 2025, show each reviewer with at least one merged review, along with how many unique repos they reviewed, how many of their reviews were merged, and the most recent date one of their reviews was opened.
Some reviewers are thorough. Others are fast.
Tables
code_reviews
Columns: review_id INTEGER, repo_name TEXT, author TEXT, reviewer TEXT, status TEXT, comments INTEGER, opened_at TEXT, merged TEXT
| review_id | repo_name | author | reviewer | status | comments | opened_at | merged |
|---|---|---|---|---|---|---|---|
| 1053 | backend-api | bob | eve | changes_requested | 3 | 2026-02-02 | 2026-02-05 |
| 1106 | infra | charlie | frank | pending | 6 | 2026-03-03 | 2026-03-06 |
| 1159 | ml-pipeline | dana | grace | Approved | 9 | 2026-04-04 | 2026-04-07 |
| 1212 | mobile-app | eve | hank | PENDING | 12 | 2026-05-05 | NULL |
| 1265 | data-platform | frank | alice | merged | 15 | 2026-06-06 | 2026-06-09 |
| 1318 | frontend | grace | bob | approved | 18 | 2026-07-07 | 2026-07-10 |
| 1371 | backend-api | hank | charlie | changes_requested | 21 | 2026-08-08 | 2026-08-11 |
| 1424 | infra | alice | NULL | pending | 24 | 2026-09-09 | NULL |
| 1477 | ml-pipeline | bob | eve | Approved | 27 | 2026-01-10 | 2026-01-13 |
| 1530 | mobile-app | charlie | frank | PENDING | 30 | 2026-02-11 | 2026-02-14 |
Expected output
| reviewer | repos_reviewed | merged_reviews | latest_review_opened |
|---|---|---|---|
| alice | 3 | 17 | 2026-09-06 |
| bob | 3 | 17 | 2026-09-07 |
| charlie | 3 | 17 | 2026-09-04 |
| eve | 3 | 18 | 2026-09-06 |
| frank | 3 | 18 | 2026-09-07 |
Worked solution and explanation
What this really is
This is two populations counted in one summary, dressed up as a reviewer audit. Every review in the window feeds the repo count; only the ones with a merge date feed the merged count. Anyone can write a GROUP BY reviewer. The trap is filtering merged rows out early, or trusting status, so both numbers describe the same rows. Get it wrong and every reviewer looks like they merged everything they touched.
Step 1: Slice the window on the open date
opened_at >= DATE '2025-01-01' compares a timestamp against a calendar boundary. The window is about when the review was opened; merged has nothing to do with it.
Step 2: Measure breadth with unique repos
A reviewer hits the same repo many times, so COUNT(*) measures volume, not breadth. COUNT(DISTINCT repo_name) gives how many different repos they touched.
Step 3: Tally merges by the date, not the text
status holds 'approved', 'Approved' and 'merged' on reviews that never shipped. A present merged date is the only proof, so the tally is COUNT(merged), never a match on the status label.
Step 4: Keep reviewers with at least one merge
The bar runs after grouping, so it sits in HAVING, spelled as a conditional tally: SUM(CASE WHEN merged IS NOT NULL THEN 1 ELSE 0 END) >= 1. It also removes the NULL reviewer bucket: unassigned reviews never merged, so that group scores zero.
SELECT reviewer,
COUNT(DISTINCT repo_name) AS repos_reviewed,
COUNT(merged) AS merged_reviews,
MAX(opened_at) AS latest_review_opened
FROM code_reviews
WHERE opened_at >= DATE '2025-01-01'
GROUP BY reviewer
HAVING SUM(CASE WHEN merged IS NOT NULL THEN 1 ELSE 0 END) >= 1- Filter first
WHERE merged IS NOT NULLbefore grouping:repos_reviewedshrinks to merged repos andmerged_reviewsequals the row count. Two columns, one population.- Count conditionally
- Keep every review in the window and let the aggregates pick:
COUNT(merged)sees only shipped rows,COUNT(DISTINCT repo_name)sees all of them. Same scan, different rows.
Common follow-up questions
- How would you report each reviewer's merge rate alongside the counts? (Tests reusing the merged tally as a numerator over `COUNT(*)`.)
- What if `status` were cleaned up and trustworthy: would you still key on `merged`? (Tests reasoning about source of truth versus derived labels.)
- How would you include reviewers with no merges, showing zero? (Tests moving the bar out of `HAVING` and what that does to the `NULL` reviewer bucket.)