cswork / libraryOpen practice workspace

Coding questions · Meta

Compute multi-account activity and unread percentages in SQL

This question evaluates SQL-based data manipulation and analytics skills, including joining daily snapshots to event tables, applying time-window filters, mapping multiple accounts to a person, and computing aggregate counts and unread percentages.

You are given two tables. Use them as the source of truth and do not assume any other data.

Table: notifications
+--------+------------+------------+-------------------+--------+
| userid | ds | event_time | notification_type | status |
+--------+------------+------------+-------------------+--------+
| 111 | 2025-08-20 | 1766270400 | direct | unread |
| 112 | 2025-08-15 | 1765845600 | group | read |
| 114 | 2025-08-05 | 1764981600 | direct | unread |
| 115 | 2025-08-28 | 1766896800 | mention | read |
| 117 | 2025-08-09 | 1765327200 | direct | unread |
| 118 | 2025-08-30 | 1767069600 | group | unread |
| 119 | 2025-08-31 | 1767156000 | direct | read |
| 120 | 2025-08-31 | 1767159600 | mention | unread |
+--------+------------+------------+-------------------+--------+

Columns:

  • userid INT: account identifier.
  • ds DATE: event date (UTC).
  • event_time BIGINT: Unix epoch seconds for the event.
  • notification_type STRING: e.g., 'direct', 'group', 'mention'.
  • status STRING: 'unread' or 'read'.

Table: dim_circle_people (daily snapshot; one row per (person_id, userid, ds))

+-----------+--------+------------------+---------------+------------+
| person_id | userid | last_action_date | creation_date | ds |
+-----------+--------+------------------+---------------+------------+
| 1 | 111 | 2025-08-20 | 2024-01-01 | 2025-09-01 |
| 1 | 112 | 2025-08-15 | 2024-03-01 | 2025-09-01 |
| 2 | 113 | 2025-07-30 | 2022-10-10 | 2025-09-01 |
| 3 | 114 | 2025-08-05 | 2023-04-05 | 2025-09-01 |
| 3 | 115 | 2025-08-28 | 2023-05-10 | 2025-09-01 |
| 3 | 116 | 2025-06-10 | 2023-06-12 | 2025-09-01 |
| 4 | 117 | 2025-08-09 | 2025-08-01 | 2025-09-01 |
| 4 | 118 | 2025-08-30 | 2025-08-15 | 2025-09-01 |
| 4 | 119 | 2025-08-31 | 2025-08-20 | 2025-09-01 |
| 4 | 120 | 2025-08-31 | 2025-08-25 | 2025-09-01 |
+-----------+--------+------------------+---------------+------------+

Columns:

  • person_id INT: real person cluster id (one person may own multiple accounts/userids).
  • userid INT: account id belonging to that person.
  • last_action_date DATE: date of the account's most recent action.
  • creation_date DATE: account creation date.
  • ds DATE: snapshot date; use the latest snapshot.

Definitions for this problem:

  • Treat 'last month' as 2025-08-01 to 2025-08-31 inclusive.
  • Consider an account 'active during last month' if last_action_date is between 2025-08-01 and 2025-08-31 (inclusive) in the dim_circle_people snapshot where ds = '2025-09-01'.
  • A person is 'multi-account active' if they have >=2 accounts that meet the above activity rule.
  • An 'unread notification' is any notifications row with status = 'unread' and ds between 2025-08-01 and 2025-08-31 (inclusive).

Tasks: (a) Write a single SQL query that returns exactly three numbers in one row: the count of people with exactly two active accounts, exactly three active accounts, and more than three active accounts, all based on the above definitions. Name the output columns two_accts, three_accts, gt_three_accts. (b) Among people who are 'multi-account active' (>=2 active accounts by the above rule), write a SQL query that returns one row with a single column percent_unread: the percentage of those people who have at least one unread notification on any of their accounts during 2025-08-01..2025-08-31. Compute as 100.0 * numerator / denominator and round to two decimals. Ensure each person is counted at most once in the numerator even if they have multiple unread notifications across accounts. Edge cases to handle explicitly: do not count accounts with last_action_date outside August 2025; only use ds='2025-09-01' rows from dim_circle_people; ignore notifications outside August 2025; avoid double-counting per person; return 0.00 if the denominator is zero.

Count people by number of active accounts in August 2025

You are given two tables: dim_circle_people (a daily snapshot of which userids belong to which real person) and notifications.

Use ONLY the snapshot rows where dim_circle_people.ds = '2025-09-01'.

Definitions:

  • Treat “last month” as the date range 2025-08-01 to 2025-08-31 inclusive.
  • An account (userid) is considered active during last month if last_action_date is between 2025-08-01 and 2025-08-31 inclusive.
  • A person is multi-account active if they have at least 2 active accounts by the rule above.

Task (a): Write a single SQL query that returns exactly three numbers in one row:

  • two_accts: count of people with exactly 2 active accounts
  • three_accts: count of people with exactly 3 active accounts
  • gt_three_accts: count of people with more than 3 active accounts

Important edge cases:

  • Do not count accounts with last_action_date outside August 2025 (or NULL).
  • Only use dim_circle_people rows from ds = '2025-09-01'.
  • Return 0 for a bucket if no people fall into it.

Table notifications

columntypeconstraints
useridINTNOT NULL
dsDATENOT NULL
event_timeBIGINT
notification_typeVARCHAR(20)
statusVARCHAR(10)NOT NULL

Sample data:

dsevent_timenotification_typestatususerid
2025-08-201766270400directunread111
2025-08-151765845600groupread112
2025-08-051764981600directunread114
2025-08-281766896800mentionread115
2025-08-091765327200directunread117
2025-08-301767069600groupunread118
2025-08-311767156000directread119
2025-08-311767159600mentionunread120
2025-08-201766274000groupunread116
2025-08-121765586400directunread121
2025-08-131765672800mentionunread123
2025-08-111765500000groupread124
2025-07-311764463200directunread126
2025-09-011767220000directunread124
2025-08-101765413600directunread999
2025-08-161765932000NULLread112

Table dim_circle_people

columntypeconstraints
person_idINTNOT NULL
useridINTNOT NULL
last_action_dateDATE
creation_dateDATENOT NULL
dsDATENOT NULL

Sample data:

creation_datedslast_action_dateperson_iduserid
2024-01-012025-09-012025-08-201111
2024-03-012025-09-012025-08-151112
2022-10-102025-09-012025-07-302113
2023-04-052025-09-012025-08-053114
2023-05-102025-09-012025-08-283115
2023-06-122025-09-012025-06-103116
2025-08-012025-09-012025-08-094117
2025-08-152025-09-012025-08-304118
2025-08-202025-09-012025-08-314119
2025-08-252025-09-012025-08-314120
2025-07-012025-09-012025-08-105121
2025-01-012025-09-01NULL6122
2025-02-022025-09-012025-08-126123
2025-01-102025-09-012025-08-027124
2025-02-102025-09-012025-08-017125
2025-03-102025-09-012025-08-317126
2024-01-012025-08-012025-07-311111
2024-03-012025-08-012025-07-151112
2025-08-012025-08-012025-07-294117

Expected output

One row with three integer columns showing how many people have exactly 2, exactly 3, and more than 3 active accounts in August 2025 (based on the ds='2025-09-01' snapshot).

gt_three_acctsthree_acctstwo_accts
112

Hints

  1. First, filter to the latest snapshot (ds='2025-09-01') and count August-active accounts per person_id.
  2. Then turn per-person counts into 3 buckets using conditional aggregation.

Percent of multi-account active people with at least one unread notification in August 2025

You are given two tables: dim_circle_people (a daily snapshot) and notifications.

Use ONLY the snapshot rows where dim_circle_people.ds = '2025-09-01'.

Definitions:

  • Treat “last month” as 2025-08-01 to 2025-08-31 inclusive.
  • An account is active during last month if last_action_date is between 2025-08-01 and 2025-08-31 inclusive.
  • A person is multi-account active if they have >= 2 active accounts by the rule above.
  • An unread notification is any notifications row with status = 'unread' and notifications.ds between 2025-08-01 and 2025-08-31 inclusive.

Task (b): Among people who are multi-account active, return one row with a single column percent_unread: the percentage of those people who have at least one unread notification on any of their accounts during 2025-08-01..2025-08-31.

  • Compute as 100.0 * numerator / denominator
  • Round to two decimals.
  • Count each person at most once in the numerator even if they have multiple unread notifications across accounts.
  • Return 0.00 if the denominator is 0.

Edge cases to handle explicitly:

  • Only use dim_circle_people.ds='2025-09-01'.
  • Ignore notifications outside August 2025.
  • Avoid double-counting per person.

Table notifications

columntypeconstraints
useridINTNOT NULL
dsDATENOT NULL
event_timeBIGINT
notification_typeVARCHAR(20)
statusVARCHAR(10)NOT NULL

Sample data:

dsevent_timenotification_typestatususerid
2025-08-201766270400directunread111
2025-08-151765845600groupread112
2025-08-051764981600directunread114
2025-08-281766896800mentionread115
2025-08-091765327200directunread117
2025-08-301767069600groupunread118
2025-08-311767156000directread119
2025-08-311767159600mentionunread120
2025-08-201766274000groupunread116
2025-08-121765586400directunread121
2025-08-131765672800mentionunread123
2025-08-111765500000groupread124
2025-07-311764463200directunread126
2025-09-011767220000directunread124
2025-08-101765413600directunread999
2025-08-161765932000NULLread112

Table dim_circle_people

columntypeconstraints
person_idINTNOT NULL
useridINTNOT NULL
last_action_dateDATE
creation_dateDATENOT NULL
dsDATENOT NULL

Sample data:

creation_datedslast_action_dateperson_iduserid
2024-01-012025-09-012025-08-201111
2024-03-012025-09-012025-08-151112
2022-10-102025-09-012025-07-302113
2023-04-052025-09-012025-08-053114
2023-05-102025-09-012025-08-283115
2023-06-122025-09-012025-06-103116
2025-08-012025-09-012025-08-094117
2025-08-152025-09-012025-08-304118
2025-08-202025-09-012025-08-314119
2025-08-252025-09-012025-08-314120
2025-07-012025-09-012025-08-105121
2025-01-012025-09-01NULL6122
2025-02-022025-09-012025-08-126123
2025-01-102025-09-012025-08-027124
2025-02-102025-09-012025-08-017125
2025-03-102025-09-012025-08-317126
2024-01-012025-08-012025-07-311111
2024-03-012025-08-012025-07-151112
2025-08-012025-08-012025-07-294117

Expected output

One row with percent_unread, the percent of multi-account active people (>=2 August-active accounts) who have at least one unread notification in August 2025 on any of their accounts. Rounded to two decimals.

percent_unread
75

Hints

  1. Compute the denominator as the number of distinct person_id with >=2 active accounts in August (from the latest snapshot).
  2. For the numerator, find distinct person_id (from that same cohort) that have at least one unread notification in August; use DISTINCT to avoid double-counting.