Auth Endpoints
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
- City and County of San Francisco
Problem
Our credential submissions are the POST requests to the auth routes in api_calls, and clients log the HTTP method in whatever case they send it, so 'post' and 'POST' are the same request. Pull those calls with their latency in the order they were logged, earliest first.
Not all endpoints are visible to everyone.
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
| call_time | endpoint | method | latency |
|---|---|---|---|
| 2023-01-23 22:46:00 | /api/v1/auth/login | POST | 381.6 |
| 2024-03-07 10:22:00 | /api/v1/auth/login | post | 589.2 |
| 2024-09-02 05:17:00 | /api/v1/auth/logout | POST | 502.7 |
| 2024-10-14 17:53:00 | /api/v1/auth/logout | post | 710.3 |
| 2025-11-09 16:52:00 | /api/v1/auth/login | POST | 1108.2 |
Worked solution and explanation
What this really is
This is a dirty-categorical filter dressed up as a security review. The route side is the easy half: endpoint LIKE '%auth%' catches both /api/v1/auth/login and /api/v1/auth/logout. The real test is method, which this log stores as 'POST' for most clients and 'post' for some. Anyone who writes method = 'POST' gets 11 rows, sees uppercase in the result and ships it. Six of the 17 credential submissions are gone, and nothing in the output tells you.
Getting there
Step 1: Profile method before filtering on it
Before trusting a literal, look at what the column holds. method has seven spellings for five verbs: 'get' and 'post' sit beside 'GET' and 'POST'. That one look decides the whole query.
Step 2: Fold the case, then compare
LOWER(method) = 'post' collapses both spellings into one value. You fold the column, not the literal: the literal is already in the case you chose.
Step 3: Match the route by substring
Auth traffic is split across login and logout, so equality against either path loses the other. endpoint LIKE '%auth%' takes both. On this table the paths are already lowercase, so the route side needs no folding.
Step 4: Sort by call_time
'Earliest first' means call_time. call_id is not assigned in time order here, so sorting by it scrambles the timeline the reviewer reads.
SELECT call_time, endpoint, method, latency
FROM api_calls
WHERE endpoint LIKE '%auth%'
AND LOWER(method) = 'post'
ORDER BY call_timeSELECT call_time, endpoint, method, latency
FROM api_calls
WHERE endpoint LIKE '%auth%'
AND method = 'POST'
ORDER BY call_timeReturns 11 of the 17 rows: every lowercase 'post' submission is dropped.
- Literal as written
method = 'POST'returns 11 rows and drops the 6 logged as 'post'. The output is still tidy, which is exactly why nobody catches it.- Case folded
LOWER(method) = 'post'returns all 17. Themethodcolumn in the result still shows both spellings, because the folding happens only in the filter.
Common follow-up questions
- How would you confirm no other spelling of POST exists, say with stray whitespace? (Tests whether the candidate profiles a categorical rather than guessing its values.)
- The security team now wants only the failed submissions. Which column tells you that, and what is your cutoff? (Tests reading `status` as a range of codes rather than a single value.)
- If this ran daily over 50M rows partitioned on `call_time`, how would you keep it cheap? (Tests partition pruning and the cost of wrapping a column in a function.)