Auth Endpoint Callers
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
Problem
Endpoint paths bury the authentication routes inside the versioned path, so a call counts when its endpoint contains 'auth' anywhere, and the security review needs every such call in api_calls tied back to the account in users that made it. List the user's ID, username, email, call ID and endpoint, by user ID and then call ID, lowest first.
Identify users who have called authentication API endpoints
Tables
users
Columns: user_id INTEGER, username TEXT, email TEXT, signup_date TEXT, account_status TEXT, age_bucket TEXT
| user_id | username | signup_date | account_status | age_bucket | |
|---|---|---|---|---|---|
| 100 | alice | alice@example.com | 2025-02-02 | inactive | 25-34 |
| 197 | aaron42 | aaron42@example.com | 2026-03-03 | suspended | 35-44 |
| 294 | amelia | amelia@example.com | 2024-04-04 | pending_verification | 45-54 |
| 391 | arjun | arjun@example.com | 2025-05-05 | active | 55-64 |
| 488 | ava99 | ava99@example.com | 2026-06-06 | inactive | 65+ |
| 585 | andrew_k | andrew_k@example.com | 2024-07-07 | suspended | NULL |
| 682 | anika | anika@example.com | 2025-08-08 16:34:00 | pending_verification | 18-24 |
| 779 | aiden | aiden@example.com | 2026-09-09 14:53:00 | active | 25-34 |
| 876 | aria_b | aria_b@example.com | 2024-10-10 | inactive | 35-44 |
| 973 | brian | brian@example.com | 2025-11-11 | suspended | 45-54 |
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
| user_id | username | call_id | endpoint | |
|---|---|---|---|---|
| 100 | alice | alice@example.com | 21394 | /api/v1/auth/login |
| 100 | alice | alice@example.com | 21435 | /api/v1/auth/logout |
| 197 | aaron42 | aaron42@example.com | 15268 | /api/v1/auth/login |
| 197 | aaron42 | aaron42@example.com | 15347 | /api/v1/auth/login |
| 197 | aaron42 | aaron42@example.com | 21436 | /api/v1/auth/logout |
Worked solution and explanation
What this is really asking
This is an enrichment join with a substring filter, dressed up as a security audit. api_calls already has call_id, endpoint and user_id, which tempts people to answer from one table, but username and email live only in users. The other half is the filter: every endpoint is a full path like '/api/v1/auth/login', so endpoint = 'auth' matches nothing. The review comes back empty and quietly reports that nobody touched authentication when 120 calls did.
Break down the requirements
Step 1: Filter calls to auth endpoints
endpoint LIKE '%auth%' on api_calls. The leading wildcard kills any btree index; this is a scan or trigram lookup.
Step 2: Join to users
INNER JOIN on user_id. Anonymous calls with null user_id drop out by design; the seed has several anonymous logout hits that should not appear.
Step 3: Project and sort
Select the five requested columns and sort by u.user_id, then call_id. Both keys are returned columns and unique together, so the order is fixed. call_id is not call_time: user 197's June login retries carry lower ids than their February logout.
The solution
SELECT
u.user_id,
u.username,
u.email,
ac.call_id,
ac.endpoint
FROM users u
INNER JOIN api_calls ac
ON u.user_id = ac.user_id
WHERE ac.endpoint LIKE '%auth%'
ORDER BY u.user_id, call_idCommon follow-up questions
Common follow-up questions
- How would you accelerate `LIKE '%auth%'` at 2B rows? (Pre-tag `endpoint` with a category column on write, or build a trigram index.)
- How do you count anonymous auth hits where `user_id IS NULL`? (UNION ALL a second query selecting from `api_calls` where `user_id IS NULL`, with NULLs for user columns.)
- What if you want one row per user instead of per call? (GROUP BY the user fields, COUNT(`call_id`), MIN/MAX(`call_time`).)