Seen and Unseen

An easy SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.

Domain
SQL
Difficulty
easy
Seniority
L4
Asked in
Airbnb

Problem

Users on one platform keep complaining that they never see their two-factor codes, and the support lead wants push_notifs_2fa to settle which platform it is. Give each platform's open rate as a percentage of all codes sent to it, highest first.

Every ping lands somewhere. Not every one gets read.

Tables

push_notifs_2fa

Columns: notif_id INTEGER, user_id INTEGER, title TEXT, platform TEXT, status TEXT, sent_at TEXT, opened INTEGER, campaign TEXT

push_notifs_2fa: 10 of 200 rows
notif_iduser_idtitleplatformstatussent_atopenedcampaign
1001101Your 2FA codeandroiddelivered2026-02-02 01:07:001login_feb
1002102Your 2FA codeandroiddelivered2026-02-03 02:10:001login_feb
1003103Your 2FA codeandroiddelivered2026-02-04 03:15:000login_feb
1004104Your 2FA codeiosdelivered2026-02-05 04:20:001login_feb
1005105Your 2FA codeiosdelivered2026-02-06 05:25:000login_feb
1006106Your 2FA codewebdelivered2026-02-07 06:30:001login_mar
1007107Your 2FA codewebdelivered2026-02-08 07:35:000login_mar
1008108Your 2FA codewebdelivered2026-02-09 08:40:00NULLlogin_mar
1009109Your 2FA codeiosfailed2026-02-10 09:45:000NULL
1010110Your 2FA codeandroidbounced2026-02-11 10:50:001login_mar

Expected output

First 3 of 3 rows
platformopen_rate_pct
android75
web33.333333333333336
ios33.333333333333336

Worked solution and explanation

What this really is

Beneath the support complaint, this is a per-group conditional rate. opened is a 0/1 flag, so a platform's open rate is the sum of that flag over how many codes the platform was sent. Anyone sees that much. What separates candidates is two quiet decisions: keeping the division in decimals so it does not truncate, and scoping the denominator to every code sent, including the ones whose flag never got recorded. Miss the first and every platform comes back at 0; miss the second and every platform with unrecorded flags looks better than it is.


Building it

Step 1: Sum the flag per platform

SUM(opened) over each platform is exactly its number of opens, because the column holds 0 or 1. SUM skips a NULL, so a code whose flag was never recorded adds nothing to the top of the fraction.

Step 2: Count every code sent

COUNT(*) is the denominator: every row for the platform, delivered, failed or bounced, flag recorded or not. Open rate is opens over codes sent, so nothing filters the bottom of the fraction.

Step 3: Scale and sort

Multiply the numerator by 100.0, then divide: the decimal literal forces real division and the factor of 100 turns the fraction into a percentage in one move. Sort by open_rate_pct, highest first.

Per-platform open rate
SELECT platform,
       SUM(opened) * 100.0 / COUNT(*) AS open_rate_pct
FROM push_notifs_2fa
GROUP BY platform
ORDER BY open_rate_pct DESC
`SUM(opened) / COUNT(*)`
Integer division: 1 / 4 truncates to 0 and every platform looks dead. Right denominator, wrong type.
`SUM(opened) * 100.0 / COUNT(*)`
The 100.0 promotes the expression before dividing, so 1 * 100.0 / 4 is 25.0. Same denominator, right type.

Common follow-up questions