cswork / libraryOpen practice workspace

Coding questions · The New York Times

Write SQL for content-view analytics

This question evaluates proficiency in SQL-based data manipulation and analytics, including aggregation, distinct counting, NULL handling, timestamp/hour extraction, device grouping, and row-level ordering, and is situated in the Data Manipulation (SQL/Python) domain.

Context

You work with page-view event logs and need to compute several engagement/usage summaries.

Assume a single table:

page_views

columntypedescription
view_idSTRING/INTunique event id (PK)
agent_idSTRING/INTidentifier for the viewer ("agent")
content_idSTRING/INTidentifier of the content item (nullable)
urlSTRINGURL viewed
content_typeSTRINGe.g., article, video, podcast, etc.
device_typeSTRINGone of phone, tab, desktop
viewed_atTIMESTAMPevent timestamp

Assumptions:

  • Treat mobile as device_type IN ('phone','tab'), and desktop as device_type = 'desktop'.
  • Unless otherwise specified, interpret timestamps in UTC.

Tasks (write SQL)

1) Unique contents viewed by device group

Compute, for each device group (mobile vs desktop):

  • unique_contents_viewed: number of distinct content_id values viewed (ignore NULLs)
  • total_views: total number of page-view events

Return columns: device_group, unique_contents_viewed, total_views.

Additionally (in 1–2 sentences), explain whether unique_contents_viewed and total_views will generally be equal, and why.


2) Peak usage hours by device type

For each device type (phone, tab, desktop), find the top 3 hours of day (0–23) with the highest number of views.

Return columns: device_type, hour_of_day, views.

Notes:

  • Use an hour-extraction function on viewed_at.
  • Break ties by choosing the smaller hour_of_day first.

3) Unique content count and NULL content count

Compute:

  • unique_contents_viewed: number of distinct non-NULL content_id values that were viewed
  • null_content_events: number of events where content_id IS NULL

Return columns: unique_contents_viewed, null_content_events.


4) Distribution of first-seen content type per agent per day

For each agent_id and each calendar date (derived from viewed_at), identify the first page view of that day (earliest viewed_at; if ties, use smallest view_id). Take that event’s content_type.

Then compute the distribution of these first-seen content_type values across all agent-days.

Return columns:

  • event_date
  • content_type
  • agent_days (count of agent-days whose first view had that content_type)
  • share (agent_days divided by total agent-days for that date)

Unique content viewed on Mobile vs Desktop

You are given a table of content view events. Treat device_type IN ('phone','tablet') as 'mobile' and device_type = 'desktop' as 'desktop'.

Return one row per device_group with:

  1. the number of UNIQUE contents viewed (COUNT(DISTINCT content_id), ignoring NULL content_id automatically), and
  2. the total number of view events.

This helps illustrate how "unique contents viewed" differs from "number of views".

Table content_views

columntypeconstraints
view_idINTPRIMARY KEY, NOT NULL
agent_idINTNOT NULL
device_typeVARCHAR(10)NOT NULL
content_idINT
urlVARCHAR(100)NOT NULL
content_typeVARCHAR(20)NOT NULL
viewed_atTIMESTAMPNOT NULL

Sample data:

agent_idcontent_idcontent_typedevice_typeurlview_idviewed_at
1011Newsphone/news/112025-05-30 08:05:00
1012Sportsdesktop/sports/222025-05-30 08:20:00
1011Newsphone/news/132025-05-30 09:00:00
1013Opiniontablet/opinion/342025-05-30 18:10:00
101NULLLivedesktop/live52025-05-31 07:50:00
1014Newsdesktop/news/462025-05-31 08:10:00
1015Artsphone/arts/572025-05-31 20:00:00
1022Sportstablet/sports/282025-05-30 08:15:00
1026Newsdesktop/news/692025-05-30 10:05:00
1026Newsdesktop/news/6102025-05-30 10:20:00
102NULLUnknownphone/unknown112025-05-30 22:00:00
1027Newsphone/news/7122025-05-31 08:00:00
1028Opinionphone/opinion/8132025-05-31 08:05:00
1022Sportsdesktop/sports/2142025-05-31 12:00:00
1039Newsdesktop/news/9152025-05-30 18:00:00
103NULLUnknowndesktop/404162025-05-30 18:30:00
1033Opiniontablet/opinion/3172025-05-31 07:55:00
1033Opiniontablet/opinion/3182025-05-31 08:55:00
10310Artsdesktop/arts/10192025-05-31 18:10:00

Expected output

One row per device_group ('mobile', 'desktop') showing unique content count (distinct content_id) and total view events.

device_grouptotal_viewsunique_contents
desktop95
mobile106

Hints

  1. Use CASE WHEN to map phone+tablet into a single 'mobile' group.
  2. COUNT(DISTINCT content_id) ignores NULL by default; COUNT(*) counts all events.

Peak usage hour by device group

Using the same content view events table, find the peak usage hour for each device group.

Rules:

  • device_type IN ('phone','tablet') => device_group = 'mobile'
  • device_type = 'desktop' => device_group = 'desktop'
  • Extract the hour from viewed_at.

Return the hour(s) with the maximum number of view events per device_group. If there is a tie, return all tied hours.

Table content_views

columntypeconstraints
view_idINTPRIMARY KEY, NOT NULL
agent_idINTNOT NULL
device_typeVARCHAR(10)NOT NULL
content_idINT
urlVARCHAR(100)NOT NULL
content_typeVARCHAR(20)NOT NULL
viewed_atTIMESTAMPNOT NULL

Sample data:

agent_idcontent_idcontent_typedevice_typeurlview_idviewed_at
1011Newsphone/news/112025-05-30 08:05:00
1012Sportsdesktop/sports/222025-05-30 08:20:00
1011Newsphone/news/132025-05-30 09:00:00
1013Opiniontablet/opinion/342025-05-30 18:10:00
101NULLLivedesktop/live52025-05-31 07:50:00
1014Newsdesktop/news/462025-05-31 08:10:00
1015Artsphone/arts/572025-05-31 20:00:00
1022Sportstablet/sports/282025-05-30 08:15:00
1026Newsdesktop/news/692025-05-30 10:05:00
1026Newsdesktop/news/6102025-05-30 10:20:00
102NULLUnknownphone/unknown112025-05-30 22:00:00
1027Newsphone/news/7122025-05-31 08:00:00
1028Opinionphone/opinion/8132025-05-31 08:05:00
1022Sportsdesktop/sports/2142025-05-31 12:00:00
1039Newsdesktop/news/9152025-05-30 18:00:00
103NULLUnknowndesktop/404162025-05-30 18:30:00
1033Opiniontablet/opinion/3172025-05-31 07:55:00
1033Opiniontablet/opinion/3182025-05-31 08:55:00
10310Artsdesktop/arts/10192025-05-31 18:10:00

Expected output

One or more rows per device_group listing the hour(s) with the maximum number of views and the corresponding count.

device_groupview_countview_hour
desktop318
mobile58

Hints

  1. Aggregate counts by device_group and extracted hour first.
  2. Use DENSE_RANK (or MAX() + join) to keep all ties for the peak.

Count unique contents viewed and NULL content_id events

Using the content view events table, compute:

  • the number of unique contents viewed (distinct non-NULL content_id), and
  • the number of view events where content_id is NULL.

Return a single row with these two metrics.

Table content_views

columntypeconstraints
view_idINTPRIMARY KEY, NOT NULL
agent_idINTNOT NULL
device_typeVARCHAR(10)NOT NULL
content_idINT
urlVARCHAR(100)NOT NULL
content_typeVARCHAR(20)NOT NULL
viewed_atTIMESTAMPNOT NULL

Sample data:

agent_idcontent_idcontent_typedevice_typeurlview_idviewed_at
1011Newsphone/news/112025-05-30 08:05:00
1012Sportsdesktop/sports/222025-05-30 08:20:00
1011Newsphone/news/132025-05-30 09:00:00
1013Opiniontablet/opinion/342025-05-30 18:10:00
101NULLLivedesktop/live52025-05-31 07:50:00
1014Newsdesktop/news/462025-05-31 08:10:00
1015Artsphone/arts/572025-05-31 20:00:00
1022Sportstablet/sports/282025-05-30 08:15:00
1026Newsdesktop/news/692025-05-30 10:05:00
1026Newsdesktop/news/6102025-05-30 10:20:00
102NULLUnknownphone/unknown112025-05-30 22:00:00
1027Newsphone/news/7122025-05-31 08:00:00
1028Opinionphone/opinion/8132025-05-31 08:05:00
1022Sportsdesktop/sports/2142025-05-31 12:00:00
1039Newsdesktop/news/9152025-05-30 18:00:00
103NULLUnknowndesktop/404162025-05-30 18:30:00
1033Opiniontablet/opinion/3172025-05-31 07:55:00
1033Opiniontablet/opinion/3182025-05-31 08:55:00
10310Artsdesktop/arts/10192025-05-31 18:10:00

Expected output

A single row with two columns: distinct non-NULL content_id count and the number of rows with NULL content_id.

null_content_viewsunique_contents
310

Hints

  1. COUNT(DISTINCT ...) will ignore NULLs, but SUM(CASE WHEN ... IS NULL ...) will count them.
  2. Return a single row (no GROUP BY needed).