Who's Looking

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
L3
Asked in
Airbnb

Problem

The search quality team wants to know which search terms are reaching the widest audience. For each term, count how many different users searched it, with the widest reach first.

Every search is a question someone needed answered. Count the people asking.

Tables

search_queries

Columns: query_id INTEGER, user_id INTEGER, search_term TEXT, results_count INTEGER, clicked_result INTEGER, query_time TEXT

search_queries: 10 of 200 rows
query_iduser_idsearch_termresults_countclicked_resultquery_time
2071100laptop deals1722026-02-02 01:11:00
2142197phone case iphone 153432026-03-03 02:22:00
2213294usb-c cable 6ft51NULL2026-04-04 03:33:00
2284NULLgaming mouse6852026-05-05 04:44:00
2355488mechanical keyboard8562026-06-06 05:55:00
24265854k monitor102NULL2026-07-07 06:06:00
2497682standing desk11982026-08-08 07:17:00
2568NULLwebcam 1080p13692026-09-09 08:28:00
2639876bluetooth speaker153NULL2026-01-10 09:39:00
2710973smart watch17012026-02-11 10:50:00

Expected output

First 5 of 33 rows
search_termunique_searchers
4k monitor5
bluetooth speaker5
external ssd 1tb4
4k monitor1
wireless headphones0

Worked solution and explanation

What this problem is really about

This is a per-group unique count wearing an audience-reach costume. The skill being probed: can you separate searches from searchers? The table stores one row per query, so a term one obsessive user hit ten times has ten rows, while a term ten different people each searched once also has ten rows. Reach only cares about the second kind. The trap is reaching for COUNT(*) or COUNT(user_id): both count rows, so the repeat-searcher term looks just as broad as the genuinely popular one. DISTINCT is what collapses the same user back to one.


Walking through it

Step 1: Bucket by term

One output row per search term, so the term is the grouping key. Everything else is computed within each of those buckets.

Step 2: Count distinct searchers, not searches

Inside each bucket, COUNT(DISTINCT user_id) folds every repeated searcher down to one and silently drops the NULL user_id rows (anonymous searches), giving the true count of different people. Look at 'laptop deals' in the sample: user 100 appears twice but the reach is 3, not 4.

Step 3: Order by reach, break ties cleanly

Sort by the count descending so the widest-reach terms surface first. A secondary sort on search_term keeps ties (here gaming mouse and smart watch both at 2) in a stable, predictable order.


The solution

Unique searchers per term
SELECT search_term,
       COUNT(DISTINCT user_id) AS unique_searchers
FROM search_queries
GROUP BY search_term
ORDER BY unique_searchers DESC, search_term
COUNT(`user_id`)
Counts rows, so repeat searches by one person inflate the number. Reports 4 for 'laptop deals'.
COUNT(DISTINCT `user_id`)
Counts people, folding a user's repeat searches into one. Reports 3 for 'laptop deals'. This is the reach metric.

Common follow-up questions