Survey Response Rate per Impression and per Unique User in SQL

Read the full interview experience this question came from →

Quick Overview

A SQL exercise on a survey event table that logs survey impressions and responses with 1-to-5 ratings. It asks for the survey response rate computed two ways in one PostgreSQL query, per impression and per unique user, testing conditional counting, distinct counts and division that avoids integer truncation.

Survey Response Rate per Impression and per Unique User in SQL

Company: Meta

Role: Data Scientist

Category: Data Manipulation (SQL/Python)

Difficulty: medium

Interview Round: Technical Screen

An app shows short in-app surveys to its users, and users who answer give a rating from 1 to 5. Every time a survey is shown and every time a user answers, one row is written to an event table. Compute the survey response rate in two ways: 1. **Impression level:** the number of responses divided by the number of survey impressions. 2. **Unique-user level:** the number of distinct users who responded at least once, divided by the number of distinct users who were shown at least one survey. The report asks for the impression-level rate first and the unique-user rate as a follow-up. This version asks for both in one query and fixes rounding and empty-table behavior. ### Input Table(s) **`survey`**: one row per survey event. The table has no primary key; identical rows are separate events. | Column | Type | Meaning | | --- | --- | --- | | `userid` | INTEGER | The user who was shown or answered the survey | | `date` | DATE | Calendar date of the event | | `survey_event` | TEXT | `impression` when the survey was shown, `response` when the user answered it | | `response` | INTEGER | The rating from 1 to 5 on `response` rows; NULL on `impression` rows | ### Output Contract Write one read-only PostgreSQL query (`SELECT`, optionally with `WITH`) that returns exactly one row with these columns, in this order: | Column | Type | Meaning | | --- | --- | --- | | `impression_response_rate` | numeric | Number of `response` rows divided by the number of `impression` rows, rounded to 4 decimal places | | `user_response_rate` | numeric | Number of distinct users with at least one `response` row divided by the number of distinct users with at least one `impression` row, rounded to 4 decimal places | The result always has exactly one row, so no `ORDER BY` is needed. Both rates are NULL when the table has no `impression` rows, including when the table is empty. ### Example `survey`: | userid | date | survey_event | response | | --- | --- | --- | --- | | 1 | 2025-05-01 | impression | NULL | | 1 | 2025-05-01 | response | 4 | | 1 | 2025-05-03 | impression | NULL | | 2 | 2025-05-02 | impression | NULL | | 2 | 2025-05-02 | impression | NULL | | 3 | 2025-05-02 | impression | NULL | | 3 | 2025-05-04 | response | 2 | | 4 | 2025-05-05 | impression | NULL | | 5 | 2025-05-03 | impression | NULL | | 5 | 2025-05-03 | response | 5 | Expected result: | impression_response_rate | user_response_rate | | --- | --- | | 0.4286 | 0.6000 | - There are 7 impression rows (users 1 and 2 have two each, users 3, 4 and 5 one each; user 2's two identical rows both count) and 3 response rows, so the impression-level rate is 3/7, which rounds to 0.4286. - Users 1, 2, 3, 4 and 5 were shown a survey, and users 1, 3 and 5 responded, so the unique-user rate is 3/5 = 0.6000. ### Constraints and Clarifications - `survey_event` is always exactly `impression` or `response`, in lowercase. - `response` is NULL on every `impression` row and an integer from 1 to 5 on every `response` row. `userid`, `date` and `survey_event` are never NULL. - Every response answers an impression shown to the same user, so a user never has more `response` rows than `impression` rows, and every user with a `response` row also has at least one `impression` row. Both rates lie between 0 and 1. - Identical rows are separate events, and each one counts toward the impression-level rate. - A user counts once in the unique-user rate, however many impressions or responses they have. - Both rates cover the whole table; `date` is not used for filtering. - Each rate is the exact ratio rounded to 4 decimal places, so 3/7 is reported as 0.4286, never as 0. ```hint Count the same kind of thing One rate compares rows with rows and the other compares people with people. Make sure each numerator counts the same kind of thing as its denominator. ```

Overview: A SQL exercise on a survey event table that logs survey impressions and responses with 1-to-5 ratings. It asks for the survey response rate computed two ways in one PostgreSQL query, per impression and per unique user, testing conditional counting, distinct counts and division that avoids integer truncation.

Read the full Meta Data Scientist interview experience this question came from

Meta logo
Meta
Sep 14, 2026
mediumData ScientistTechnical ScreenData Manipulation (SQL/Python)
0
0

An app shows short in-app surveys to its users, and users who answer give a rating from 1 to 5. Every time a survey is shown and every time a user answers, one row is written to an event table. Compute the survey response rate in two ways:

  1. Impression level: the number of responses divided by the number of survey impressions.
  2. Unique-user level: the number of distinct users who responded at least once, divided by the number of distinct users who were shown at least one survey.

The report asks for the impression-level rate first and the unique-user rate as a follow-up. This version asks for both in one query and fixes rounding and empty-table behavior.

Input Table(s)

survey: one row per survey event. The table has no primary key; identical rows are separate events.

ColumnTypeMeaning
useridINTEGERThe user who was shown or answered the survey
dateDATECalendar date of the event
survey_eventTEXTimpression when the survey was shown, response when the user answered it
responseINTEGERThe rating from 1 to 5 on response rows; NULL on impression rows

Output Contract

Write one read-only PostgreSQL query (SELECT, optionally with WITH) that returns exactly one row with these columns, in this order:

ColumnTypeMeaning
impression_response_ratenumericNumber of response rows divided by the number of impression rows, rounded to 4 decimal places
user_response_ratenumericNumber of distinct users with at least one response row divided by the number of distinct users with at least one impression row, rounded to 4 decimal places

The result always has exactly one row, so no ORDER BY is needed. Both rates are NULL when the table has no impression rows, including when the table is empty.

Example

survey:

useriddatesurvey_eventresponse
12025-05-01impressionNULL
12025-05-01response4
12025-05-03impressionNULL
22025-05-02impressionNULL
22025-05-02impressionNULL
32025-05-02impressionNULL
32025-05-04response2
42025-05-05impressionNULL
52025-05-03impressionNULL
52025-05-03response5

Expected result:

impression_response_rateuser_response_rate
0.42860.6000
  • There are 7 impression rows (users 1 and 2 have two each, users 3, 4 and 5 one each; user 2's two identical rows both count) and 3 response rows, so the impression-level rate is 3/7, which rounds to 0.4286.
  • Users 1, 2, 3, 4 and 5 were shown a survey, and users 1, 3 and 5 responded, so the unique-user rate is 3/5 = 0.6000.

Constraints and Clarifications

  • survey_event is always exactly impression or response , in lowercase.
  • response is NULL on every impression row and an integer from 1 to 5 on every response row. userid , date and survey_event are never NULL.
  • Every response answers an impression shown to the same user, so a user never has more response rows than impression rows, and every user with a response row also has at least one impression row. Both rates lie between 0 and 1.
  • Identical rows are separate events, and each one counts toward the impression-level rate.
  • A user counts once in the unique-user rate, however many impressions or responses they have.
  • Both rates cover the whole table; date is not used for filtering.
  • Each rate is the exact ratio rounded to 4 decimal places, so 3/7 is reported as 0.4286, never as 0.