Calculate Daily Survey Response Rates by Country
MetaData Scientist · Technical ScreenLast updated
Write a PostgreSQL query to compute daily survey response rates at the country level using distinct user counts while handling orphan response logs and edge cases.
Problem Statement
Meta frequently runs in-app micro-surveys to measure user sentiment and product satisfaction. You are given two tables tracking survey delivery and completion: survey_impressions and survey_responses.
Write a PostgreSQL query to calculate the daily survey response rate for each country. The response rate is defined as the number of distinct users who submitted a valid survey response divided by the number of distinct users who were shown a survey impression on that date.
Requirements:
- A response is only considered valid if it joins back to an impression recorded in
survey_impressionson that same date. Orphan responses (responses missing an impression record or referencing an impression from another day) must not be counted toward that date's response metric. - Dates should be extracted from
impression_timein UTC (YYYY-MM-DD). - Calculate:
survey_date: Date of the impression (YYYY-MM-DD).country: Country code.impression_users: Count of distinct users who received an impression on that date in that country.response_users: Count of distinct users who responded to an impression delivered on that date in that country.response_rate:response_users / impression_usersrounded to 4 decimal places. If a date/country combination has zero response users, return0.0000.
- Exclude country-date combinations where
impression_usersis 0. - Order results by
survey_datedescending, then bycountryascending.
Schema
-- survey_impressions
+-----------------+-------------+
| Column Name | Type |
+-----------------+-------------+
| impression_id | VARCHAR |
| user_id | VARCHAR |
| survey_id | VARCHAR |
| country | VARCHAR |
| impression_time | TIMESTAMP |
+-----------------+-------------+
-- survey_responses
+-----------------+-------------+
| Column Name | Type |
+-----------------+-------------+
| response_id | VARCHAR |
| impression_id | VARCHAR |
| user_id | VARCHAR |
| response_time | TIMESTAMP |
+-----------------+-------------+
Example
survey_impressions
+---------------+---------+-----------+---------+---------------------+
| impression_id | user_id | survey_id | country | impression_time |
+---------------+---------+-----------+---------+---------------------+
| imp_1 | u1 | s1 | US | 2024-03-01 10:00:00 |
| imp_2 | u1 | s1 | US | 2024-03-01 14:00:00 |
| imp_3 | u2 | s1 | US | 2024-03-01 11:30:00 |
| imp_4 | u3 | s1 | US | 2024-03-01 18:00:00 |
| imp_5 | u4 | s1 | UK | 2024-03-01 09:15:00 |
+---------------+---------+-----------+---------+---------------------+
survey_responses
+-------------+---------------+---------+---------------------+
| response_id | impression_id | user_id | response_time |
+-------------+---------------+---------+---------------------+
| res_1 | imp_1 | u1 | 2024-03-01 10:05:00 |
| res_2 | imp_2 | u1 | 2024-03-01 14:02:00 |
| res_3 | imp_3 | u2 | 2024-03-01 11:35:00 |
| res_4 | imp_999 | u99 | 2024-03-01 12:00:00 | -- orphan
+-------------+---------------+---------+---------------------+
Output
+-------------+---------+------------------+----------------+---------------+
| survey_date | country | impression_users | response_users | response_rate |
+-------------+---------+------------------+----------------+---------------+
| 2024-03-01 | UK | 1 | 0 | 0.0000 |
| 2024-03-01 | US | 3 | 2 | 0.6667 |
+-------------+---------+------------------+----------------+---------------+
Explanation: For US on 2024-03-01, users u1, u2, and u3 saw impressions (3 distinct users). Users u1 and u2 responded (2 distinct users). User u1 responded twice, but only counts once. res_4 is an orphan record with no matching impression and is discarded. Rate is 2 / 3 = 0.6667.
Hints
Hint 1
Start by left joining `survey_impressions` with `survey_responses` on `impression_id` so impressions without responses are preserved and orphan responses are eliminated.
Hint 2
Be careful to count `COUNT(DISTINCT i.user_id)` for impressions and `COUNT(DISTINCT r.user_id)` for responses to avoid inflating user counts due to one user having multiple impressions or responses.
Hint 3
Cast the division operands to `NUMERIC` or `DECIMAL` before dividing to prevent integer truncation in PostgreSQL, and use `ROUND(..., 4)`.
Follow-up questions
- How would you modify the query if a response is allowed to occur up to 24 hours after the impression, potentially falling on the next calendar day?
- If the tables scale to billions of rows per day, what partitioning and indexing strategy would you recommend to keep this daily aggregation fast?
- How would you adjust the query to report confidence intervals (e.g., normal approximation or Wilson score interval) alongside the response rate for each country?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.