Most Recent Token Usage
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
- OpenDoor
Problem
The security team is auditing API token activity. For each token owner, pull only the single most recently used record, working through owners from the lowest owner ID up to the highest. Include all token fields (ID, owner, scope, status, issued date, expiration, last used date, request count) and a row indicator.
Each user's latest token activity.
Tables
api_tokens
Columns: token_id INTEGER, owner_id INTEGER, scope TEXT, status TEXT, issued TEXT, expires TEXT, last_used TEXT, requests INTEGER
| token_id | owner_id | scope | status | issued | expires | last_used | requests |
|---|---|---|---|---|---|---|---|
| 1043 | 197 | write | revoked | 2025-02-02 | 2027-02-02 | 2026-02-02 | 47 |
| 1086 | 294 | admin | expired | 2025-03-03 | 2027-03-03 | 2026-03-03 | 94 |
| 1129 | 391 | read:users | Active | 2025-04-04 | 2027-04-04 | 2026-04-04 | 141 |
| 1172 | 488 | write:orders | REVOKED | 2025-05-05 | 2027-05-05 | 2026-05-05 | 188 |
| 1215 | 585 | read:analytics | active | 2025-06-06 | 2027-06-06 | 2026-06-06 | 235 |
| 1258 | 682 | full_access | revoked | 2025-07-07 | NULL | 2026-07-07 | 282 |
| 1301 | 779 | read | expired | 2025-08-08 | 2027-08-08 | 2026-08-08 | 329 |
| 1344 | 876 | write | Active | 2025-09-09 | 2027-09-09 | NULL | 0 |
| 1387 | 973 | admin | REVOKED | 2025-10-10 | 2027-10-10 | 2026-01-10 | 423 |
| 1430 | 1070 | read:users | active | 2025-11-11 | 2027-11-11 | 2026-02-11 | 470 |
Expected output
| token_id | owner_id | scope | status | issued | expires | last_used | requests | rn |
|---|---|---|---|---|---|---|---|---|
| 3150 | 100 | write | active | 2025-03-23 | 2027-03-23 | 2026-06-23 | 2350 | 1 |
| 3193 | 197 | admin | revoked | 2025-04-24 | 2027-04-24 | 2026-07-24 | 2397 | 1 |
| 3236 | 294 | read:users | expired | 2025-05-25 | 2027-05-25 | 2026-08-25 | 2444 | 1 |
| 3279 | 391 | write:orders | Active | 2025-06-26 | 2027-06-26 | 2026-09-02 | 2491 | 1 |
| 1172 | 488 | write:orders | REVOKED | 2025-05-05 | 2027-05-05 | 2026-05-05 | 188 | 1 |
Worked solution and explanation
Why this problem exists in real interviews
Per-entity latest-row queries are the bread and butter of operational reporting. Interviewers use this prompt to see whether you reach for ROW_NUMBER with a deterministic tie-break instead of GROUP BY + MAX, which silently loses non-aggregated columns or breaks on ties.
Break down the requirements
Step 1: Pick one row per owner_id, latest first
Number each token within its owner_id partition by last_used descending (token_id descending as a deterministic tie-breaker) using ROW_NUMBER().
Step 2: Tie-break on largest token_id
Keep only rn = 1, the single most recently used record per owner.
Step 3: Filter rn = 1 in the outer query and project all columns
SELECT * so every token field (token_id, owner_id, scope, status, issued, expires, last_used, requests) plus the rn row indicator is returned.
The solution
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY owner_id ORDER BY last_used DESC, token_id DESC) AS rn
FROM api_tokens
)
WHERE rn = 1
ORDER BY owner_idCommon follow-up questions
- How would you write this without a window function in plain SQLite? (Forces a self-join: `api_tokens` t JOIN (SELECT `owner_id`, MAX(`last_used`) AS mx FROM `api_tokens` GROUP BY `owner_id`) m ON ... and a follow-up tie-break by `token_id`. The candidate should mention this is more code and slower than `ROW_NUMBER`.)
- What changes if `last_used` can be NULL and you still want one row per owner? (Tests whether the candidate orders NULLs correctly. SQLite sorts NULL first in ascending and last in descending, so DESC pushes NULL last, which usually matches intent but should be stated.)
- How would you adapt this to return the latest two tokens per owner instead of one? (Trivial change to WHERE rn <= 2, but the candidate should note that the tie-break suddenly matters more because two rows are kept.)