First Contact
A medium SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.
- Domain
- SQL
- Difficulty
- medium
- Seniority
- L3
- Asked in
- Uber
Problem
The performance team is measuring first-impression latency: for the first time each user hits a given endpoint, how long that call took, counting only whole milliseconds because the timer's fractional digits are treated as noise. For every endpoint, report the average of those first-contact latencies, with the slowest first impressions at the top.
Every user's first hello to an endpoint. Timed.
Tables
api_calls
Columns: call_id INTEGER, endpoint TEXT, method TEXT, status INTEGER, latency REAL, user_id INTEGER, call_time TEXT, err_msg TEXT
| call_id | endpoint | method | status | latency | user_id | call_time | err_msg |
|---|---|---|---|---|---|---|---|
| 8079 | /api/v1/orders | POST | 200 | 4.2 | 100 | 2026-02-02 01:07:00 | NULL |
| 8158 | /api/v2/products | PUT | 200 | 7.9 | 197 | 2026-03-03 02:14:00 | NULL |
| 8237 | /api/v1/search | DELETE | 201 | 11.6 | 294 | 2026-04-04 03:21:00 | NULL |
| 8316 | /api/v1/auth/login | PATCH | 204 | 15.3 | 391 | 2026-05-05 04:28:00 | NULL |
| 8395 | /api/v1/auth/logout | get | 301 | 19 | NULL | 2026-06-06 05:35:00 | NULL |
| 8474 | /api/v2/analytics | post | 400 | 22.7 | 585 | 2026-07-07 06:42:00 | Not found |
| 8553 | /api/v1/payments | GET | 401 | 26.4 | 682 | 2026-08-08 07:49:00 | Unauthorized |
| 8632 | /api/v1/users/ | POST | 403 | 30.1 | 779 | 2026-09-09 08:56:00 | Rate limit exceeded |
| 8711 | /api/v2/products/ | PUT | 404 | 33.8 | 876 | 2026-01-10 09:03:00 | Internal server error |
| 8790 | /api/v1/users | DELETE | 500 | 37.5 | NULL | 2026-02-11 10:10:00 | Bad gateway |
Expected output
| endpoint | avg_initial_call_latency |
|---|---|
| /api/v1/auth/logout | 402.76190476190476 |
| /api/v1/search | 383.1014492753623 |
| /api/v1/auth/login | 354.6271186440678 |
| /api/v1/payments | 276.6 |
| /api/v2/products | 273.83 |
Worked solution and explanation
What this is really asking
This is a per-group first-occurrence pick wearing a latency-report costume. For every (user_id, endpoint) pair you want exactly one row, the earliest call, and only then do you average within each endpoint. The trap is AVG(latency) GROUP BY endpoint straight off the raw table. That answers 'average latency per endpoint', a different number entirely, dominated by whoever calls the most. Miss the dedup and your first-impression metric quietly becomes a traffic-weighted average of everyone's repeat traffic.
Break down the requirements
Step 1: Rank each user's calls to each endpoint by time
ROW_NUMBER() OVER (PARTITION BY user_id, endpoint ORDER BY call_time). Partitioning by both columns is the whole point: one earliest row per user per endpoint, so a chatty user contributes a single first-contact latency to each endpoint they touched, not hundreds. Ties on call_time would be broken arbitrarily; add call_id to the window's ordering if you need determinism.
Step 2: Keep only each user's first call per endpoint
Filter on rn = 1 in an outer query. A window function cannot live in WHERE, so the subquery wrapper is mandatory, not stylistic. This is the row set that represents genuine first impressions.
Step 3: Floor each latency, average per endpoint, and order
AVG(CAST(latency AS INTEGER)) floors every surviving first-contact latency to a whole millisecond before averaging, so the timer's fractional jitter never reaches the mean. Grouping by endpoint gives one number per endpoint with each user counted once, and sorting that average descending puts the slowest first impressions on top.
The solution
SELECT endpoint,
AVG(CAST(latency AS INTEGER)) AS avg_initial_call_latency
FROM (
SELECT endpoint,
latency,
ROW_NUMBER() OVER (
PARTITION BY user_id, endpoint
ORDER BY call_time
) AS rn
FROM api_calls
) first_calls
WHERE rn = 1
GROUP BY endpoint
ORDER BY avg_initial_call_latency DESCCOMMON FOLLOW-UP QUESTIONS
Common follow-up questions
- How would you report the median first-contact latency per endpoint instead of the average? (Wrap the `rn = 1` set and apply `PERCENTILE_CONT(0.5)` per endpoint, since an average hides tail behavior on latency distributions.)
- What if you wanted the average over each user's first three calls to an endpoint? (Change the filter to `rn <= 3`. The partition definition stays the same, which is why `ROW_NUMBER` scales cleanly here.)
- How would you make this incremental for a daily job? (Materialize each (user, endpoint) first `call_time` once, then only add pairs that appear for the first time in each new day instead of re-ranking 400M rows nightly.)