The Ones Who Hold Attention
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
Problem
How long do viewers stay with each creator's work, measured as the average watch_seconds across every view in content_views of the pieces that creator published in content_items? We want one figure per creator_id, with views of pieces that have no credited creator pooled into a single blank row.
Time on screen is the real vote. Find the creators earning it.
Tables
content_views
Columns: view_id INTEGER, content_id INTEGER, user_id INTEGER, device_id INTEGER, viewed_at TEXT, watch_seconds INTEGER
| view_id | content_id | user_id | device_id | viewed_at | watch_seconds |
|---|---|---|---|---|---|
| 7053 | 372 | 1361 | 404 | 2026-02-02 01:07:00 | 41 |
| 7106 | 501 | 2622 | 607 | 2026-03-03 02:14:00 | 72 |
| 7159 | 630 | 3883 | 810 | 2026-04-04 03:21:00 | 103 |
| 7212 | 759 | 5144 | 1013 | 2026-05-05 04:28:00 | 134 |
| 7265 | 888 | 6405 | 1216 | 2026-06-06 05:35:00 | 165 |
| 7318 | 1017 | 7666 | 1419 | 2026-07-07 06:42:00 | 196 |
| 7371 | 1146 | NULL | 1622 | 2026-08-08 07:49:00 | 227 |
| 7424 | 1275 | 488 | 1825 | 2026-09-09 08:56:00 | 258 |
| 7477 | 1404 | 1749 | NULL | 2026-01-10 09:03:00 | 289 |
| 7530 | 1533 | 3010 | 2231 | 2026-02-11 10:10:00 | 320 |
content_items
Columns: content_id INTEGER, title TEXT, content_type TEXT, duration_seconds INTEGER, creator_id INTEGER, publish_date TEXT
| content_id | title | content_type | duration_seconds | creator_id | publish_date |
|---|---|---|---|---|---|
| 243 | The Ultimate Guide to AI Trends | article | NULL | 197 | 2026-02-02 |
| 286 | Top 10 Mobile Apps | podcast | 154 | 294 | 2025-03-03 |
| 329 | Understanding Machine Learning [DRAFT] | short | 201 | 391 | 2026-04-04 |
| 372 | Mastering Tech Startups | livestream | 248 | 488 | 2025-05-05 |
| 415 | Introduction to Cybersecurity | video | 295 | 585 | 2026-06-06 |
| 458 | Deep Dive: Cloud Computing | article | NULL | 682 | 2025-07-07 |
| 501 | Behind the Scenes of Product Management | podcast | 389 | 779 | 2026-08-08 |
| 544 | Breaking Down DevOps | short | 436 | 876 | 2025-09-09 |
| 587 | Exploring Web Development | livestream | 483 | NULL | 2026-01-10 |
| 630 | How to Data Science | video | 530 | 1070 | 2025-11-11 |
Expected output
| creator_id | avg_watch_seconds |
|---|---|
| NULL | 1453.7142857142858 |
| 100 | 1808 |
| 197 | 2335 |
| 294 | 2110.25 |
| 391 | 1942.3333333333333 |
Worked solution and explanation
Under the attention-analytics costume, this is two-hop attribution. A row in content_views names a piece of content. It never names whose piece it is. That fact lives only in content_items. Anyone can write the GROUP BY and the AVG. What separates candidates is the bridge they pick. content_id is the real link. user_id against creator_id only looks like one. Pick the look-alike and every creator gets credited with their own browsing instead of with the attention their work earned.
The trap
Both tables carry an id that smells like a person: cv.user_id and ci.creator_id. Writing ON cv.user_id = ci.creator_id compiles, runs, and returns believable numbers. But the user_id on a view is the viewer. Equate it with a creator and you are measuring how long creators watch other people's work, which is the exact opposite of the question. The ids even overlap in value, so nothing errors and nothing looks empty.
- content_views: view_id int PK, content_id int FK, user_id int, watch_seconds int
- content_items: content_id int PK, creator_id int, title text
- content_views.content_id references content_items.content_id
Step 1: Bridge each view to its piece on content_id
Inner-join content_items to content_views on cv.content_id = ci.content_id. content_id is unique in content_items, so each view picks up exactly one piece and one creator_id. Nothing fans out, which means no dedup worries anywhere downstream.
Step 2: Average the views per creator
Group by ci.creator_id and take AVG(cv.watch_seconds) over the raw views. AVG skips views with no recorded watch time, so an untimed view neither counts as zero seconds nor pads the denominator. Pieces with no credited creator all share a NULL creator_id, so their views collapse into the one blank row the statement asks to keep.
SELECT ci.creator_id,
AVG(cv.watch_seconds) AS avg_watch_seconds
FROM content_views cv
INNER JOIN content_items ci
ON cv.content_id = ci.content_id
GROUP BY ci.creator_id
;One hop to the piece, then collapse to the creator.
- Linking on the viewer
ON cv.user_id = ci.creator_idpairs a creator with the views they themselves made. It also repeats each of those views once per piece the creator published. The numbers describe creators as an audience.- Linking on the piece
ON cv.content_id = ci.content_idpairs each view with the piece it was a view of, exactly once. The numbers describe the audience a creator's work held.
Common follow-up questions
- Also report how many timed views each creator's average is built on. (Separates `COUNT(cv.watch_seconds)` from `COUNT(*)` and checks whether they know which views the average used.)
- Restrict to views from this year only. (Tests putting a `viewed_at` predicate before aggregation and how it changes which views feed each figure.)
- Include creators whose content was never viewed. (Pushes to a `LEFT JOIN` from `content_items` so that creators whose pieces drew no views still appear.)