The Vanishing Rows

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
Clear Capital

Problem

Return each content view's ID, user ID and username by matching content_views to users on user_id. Our dashboard built on that result shows fewer views than content_views actually holds, since some views were logged with no user attached, so be ready to explain exactly which rows fall out and why.

Some records disappear when the tables meet. Figure out why.

Tables

content_views

Columns: view_id INTEGER, content_id INTEGER, user_id INTEGER, device_id INTEGER, viewed_at TEXT, watch_seconds INTEGER

content_views: 10 of 200 rows
view_idcontent_iduser_iddevice_idviewed_atwatch_seconds
705337213614042026-02-02 01:07:0041
710650126226072026-03-03 02:14:0072
715963038838102026-04-04 03:21:00103
7212759514410132026-05-05 04:28:00134
7265888640512162026-06-06 05:35:00165
73181017766614192026-07-07 06:42:00196
73711146NULL16222026-08-08 07:49:00227
7424127548818252026-09-09 08:56:00258
747714041749NULL2026-01-10 09:03:00289
75301533301022312026-02-11 10:10:00320

users

Columns: user_id INTEGER, username TEXT, email TEXT, signup_date TEXT, account_status TEXT, age_bucket TEXT

users: 10 of 200 rows
user_idusernameemailsignup_dateaccount_statusage_bucket
100alicealice@example.com2025-02-02inactive25-34
197aaron42aaron42@example.com2026-03-03suspended35-44
294 ameliaamelia@example.com2024-04-04pending_verification45-54
391arjun arjun@example.com2025-05-05active55-64
488ava99ava99@example.com2026-06-06inactive65+
585andrew_kandrew_k@example.com2024-07-07suspendedNULL
682anikaanika@example.com2025-08-08 16:34:00pending_verification18-24
779aidenaiden@example.com2026-09-09 14:53:00active25-34
876aria_baria_b@example.com2024-10-10inactive35-44
973brianbrian@example.com2025-11-11suspended45-54

Expected output

First 5 of 172 rows
view_iduser_idusername
70531361bella_q
71062622derek
71593883felix
72125144haruki
72656405jolene

Worked solution and explanation

What this really is

This is a lesson in what an equality match does with a missing key, dressed up as a dashboard bug. The query is one line; the skill being probed is whether you can explain why content_views holds 200 rows and the result holds 172. Every one of the 28 missing views has a NULL user_id, and a comparison against NULL is never true, so the match quietly discards them. The trap is treating the gap as a defect and 'fixing' it with a LEFT JOIN: the count comes back to 200, but 28 anonymous views now pose as user views with a blank username, and the real finding (views logged without a user) vanishes.

Step 1: Match each view to its user

Pair content_views with users on cv.user_id = u.user_id and keep view_id, user_id and username. users.user_id is the key of users, so each view matches at most one account and nothing fans out.

Step 2: Count what came back

The result has 172 rows against 200 in content_views. Before blaming the query, find the missing rows: the base table filtered on user_id IS NULL returns exactly 28.

Step 3: Rule out orphaned keys

A view can drop for two reasons: a NULL key, or a key with no users row. Here every non-null user_id exists in users, so the NULLs account for the whole gap. Saying that out loud turns a guess into a diagnosis.

Inner join showing NULL exclusion
SELECT cv.view_id, cv.user_id, u.username
FROM content_views cv
JOIN users u ON cv.user_id = u.user_id
Matched views only
JOIN users u ON cv.user_id = u.user_id returns 172 rows, each a view by a known account with a real username.
Every view, matched or not
LEFT JOIN users u ON cv.user_id = u.user_id returns 200 rows, 28 of them with username NULL. That is right for a report of all traffic and wrong here, because those rows are not user views.

Common follow-up questions