Average Review Comments by Author

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
L3
Asked in
Google

Problem

Engineering leadership is comparing review burden against tenure, treating each author handle as a case-sensitive identifier that must be matched exactly as it is stored. For every author who shows up in both the review log and the commit history, return the average number of comments across their code reviews alongside the date of their first commit.

Some authors get more feedback than others.

Tables

code_reviews

Columns: review_id INTEGER, repo_name TEXT, author TEXT, reviewer TEXT, status TEXT, comments INTEGER, opened_at TEXT, merged TEXT

code_reviews: 10 of 200 rows
review_idrepo_nameauthorreviewerstatuscommentsopened_atmerged
1053backend-apibobevechanges_requested32026-02-022026-02-05
1106infracharliefrankpending62026-03-032026-03-06
1159ml-pipelinedanagraceApproved92026-04-042026-04-07
1212mobile-appevehankPENDING122026-05-05NULL
1265data-platformfrankalicemerged152026-06-062026-06-09
1318frontendgracebobapproved182026-07-072026-07-10
1371backend-apihankcharliechanges_requested212026-08-082026-08-11
1424infraaliceNULLpending242026-09-09NULL
1477ml-pipelinebobeveApproved272026-01-102026-01-13
1530mobile-appcharliefrankPENDING302026-02-112026-02-14

repo_commits

Columns: commit_id INTEGER, repo_name TEXT, author TEXT, message TEXT, added INTEGER, removed INTEGER, commit_at TEXT

repo_commits: 10 of 200 rows
commit_idrepo_nameauthormessageaddedremovedcommit_at
3061backend-apibobAdd unit tests1772026-02-02 01:09:00
3122infracharlieRefactor auth module34142026-03-03 02:18:00
3183ml-pipeline charlieUpdate deps51212026-04-04 03:27:00
3244mobile-appdana Improve perf68282026-05-05 04:36:00
3305data-platformfrank Add caching layer 85352026-06-06 05:45:00
3366frontendAliceFix typo in readme102422026-07-07 06:54:00
3427backend-apiBobNULL119492026-08-08 07:03:00
3488infraaliceWIP136562026-09-09 08:12:00
3549ml-pipelinebob153632026-01-10 09:21:00
3610mobile-appcharlieAdd search endpoint170702026-02-11 10:30:00

Expected output

First 5 of 6 rows
authoravg_commentsearliest_commit
alice19.3636363636363632022-04-17 16:24:00
bob23.52022-01-02 01:09:00
charlie22.252022-02-03 02:54:00
dana19.909090909090912022-03-24 03:39:00
eve19.252022-04-21 04:24:00

Worked solution and explanation

What this really is

Strip the business framing and this is two independent per-author rollups stitched together on the author key: one average over review comments, one minimum over commit timestamps. Anyone can write the two aggregates. The whole problem lives in the join key itself, because the commit data carries both 'Alice' and 'alice', and how you treat that casing decides who appears and what their earliest commit date is.


The trap: folding the case

It is tempting to look at 'Alice' and 'alice' and decide they are obviously the same person, then wrap the key in LOWER(author). That single decision quietly rewrites the answer. 'Alice' committed earlier than 'alice', so folding the case pulls that earlier commit into the merged identity and reports a too-early first-commit date for alice, which also bumps alice up the tenure ordering. The reviews side only ever uses lowercase handles, so case-sensitive grouping naturally drops the stray capitalized commit author through the inner join.

Case-folded (wrong)
LOWER(author) merges 'Alice' into 'alice'. alice's earliest_commit jumps to the earlier 'Alice' commit and alice sorts higher than it should.
Exact match (correct)
GROUP BY author keeps 'Alice' and 'alice' separate. 'Alice' has no matching review row and is dropped by the inner join; alice's earliest_commit reflects only its own commits.

Building it

Step 1: Average the comments per author

Roll up code_reviews to one row per author with AVG(comments). This average is taken over each author's own review rows only, which is the faithful 'average number of comments on their code reviews'.

Step 2: Find each author's earliest commit

Roll up repo_commits to one row per author with MIN(commit_at). That minimum timestamp is the author's first commit, the tenure signal the ordering depends on.

Step 3: Combine the two rollups on the author key

Inner join the two per-author rollups on author. The inner join restricts the result to authors present in both sources, which excludes pure reviewers with no commits (grace, hank) and the capitalized commit-only handle 'Alice'.

Step 4: Order most tenured first

Order by earliest_commit ascending so the longest-tenured author leads, with author as a deterministic tie-break for shared timestamps.

Canonical solution
WITH review_stats AS (
    SELECT author, AVG(comments) AS avg_comments
    FROM code_reviews
    GROUP BY author
),
commit_stats AS (
    SELECT author, MIN(commit_at) AS earliest_commit
    FROM repo_commits
    GROUP BY author
)
SELECT r.author,
       r.avg_comments,
       c.earliest_commit
FROM review_stats r
JOIN commit_stats c ON r.author = c.author
;

Common follow-up questions