Presence vs. Participation
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
- Meta
Problem
The platform team is reviewing the machines in the us-east-1 region and wants to see how hard each one is working. For every node in us-east-1, list its hostname and CPU load, and label it 'busy' when CPU is at 50 percent or higher and 'idle' otherwise. Alongside each node, show the current number of active user accounts so demand sits next to the fleet at a glance.
Being in the region and being active are two very different things.
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 |
infra_nodes
Columns: node_id INTEGER, hostname TEXT, region TEXT, node_type TEXT, cpu_pct REAL, mem_pct REAL, status TEXT
| node_id | hostname | region | node_type | cpu_pct | mem_pct | status |
|---|---|---|---|---|---|---|
| 1037 | web-02 | us-west-2 | memory | 13 | 19 | stopped |
| 1074 | api-01 | eu-west-1 | storage | 26 | 38 | draining |
| 1111 | api-02 | sa-east-1 | gpu | 39 | 57 | offline |
| 1148 | db-primary | eu-central-1 | general | 52 | 76 | Running |
| 1185 | db-replica | us-east-1 | compute | 65 | 95 | STOPPED |
| 1222 | cache-01 | us-west-2 | memory | 78 | 14 | running |
| 1259 | worker-01 | eu-west-1 | Storage | NULL | NULL | stopped |
| 1296 | worker-02 | ap-south-1 | gpu | 4 | 52 | draining |
| 1333 | gpu-node-01 | eu-central-1 | general | 17 | 71 | offline |
| 1370 | WEB-03 | us-east-1 | compute | 30 | 90 | Running |
Expected output
| hostname | cpu_pct | load_state | active_users |
|---|---|---|---|
| db-replica | 65 | busy | 50 |
| WEB-03 | 30 | idle | 50 |
| api-02 | 95 | busy | 50 |
| worker-02 | 60 | busy | 50 |
| web-02 | 25 | idle | 50 |
Worked solution and explanation
What this really tests
This is a per-row classification with a fleet-wide number bolted onto every row, dressed up as a capacity check. The skill being probed: can you label each infra_nodes row inline AND carry the active-user total next to it, when the two facts live in tables that share no key? Anyone can filter to us-east-1. The trick is that the busy/idle verdict is a CASE on each node's own cpu_pct, while the active-user count is an uncorrelated scalar subquery, so there is nothing to join and nothing to group. Reach for a JOIN and you fan every node out by every active user; reach for a GROUP BY and you hand back one summary row instead of one per machine.
Walk it through
Step 1: See that there is no join
users and infra_nodes share no meaningful key: a user is not deployed on a node. If you join them, each us-east-1 node row multiplies by the number of active users and every count downstream is wrong. Say it out loud in an interview: these tables do not relate, so the active-user figure has to come in as a scalar subquery, not a join.
Step 2: Filter the region and label each node
Scope the listing with WHERE region = 'us-east-1', then label each node with CASE WHEN cpu_pct >= 50 THEN 'busy' ELSE 'idle' END. The boundary is inclusive, so a node sitting at exactly 50 is 'busy'. Writing > 50 here silently flips the label on every 50 percent node, which is the classic off-by-one an interviewer looks for.
Step 3: Carry the active-user total with a scalar subquery
Attach demand with (SELECT COUNT(*) FROM users WHERE account_status = 'active') as its own column. It is uncorrelated, so the engine computes it once and repeats the value on every node row. The account_status = 'active' filter is exact: 'suspended', 'pending_verification' and 'inactive' are not active, and counting them inflates the number.
The solution
SELECT
hostname,
cpu_pct,
CASE WHEN cpu_pct >= 50 THEN 'busy' ELSE 'idle' END AS load_state,
(SELECT COUNT(*) FROM users WHERE account_status = 'active') AS active_users
FROM infra_nodes
WHERE region = 'us-east-1'Common follow-up questions
- What changes if the active-user count should be specific to each node's region rather than a single global number? (Tests whether the candidate reaches for a correlated subquery or a windowed COUNT when the aggregate must vary by the outer row. The active-user total is global today, but per-region demand would need correlation.)
- Add a middle 'warm' tier for nodes between 30 and 50 percent CPU. How do the CASE branches and their boundaries change? (Tests CASE fluency and boundary reasoning. A third tier forces them to order the WHEN branches correctly and decide where the inclusive boundaries fall.)
- If this were embedded in a much larger query, would the active-user subquery be re-evaluated per row, and how would you guarantee it runs only once? (Tests understanding that an uncorrelated scalar subquery is evaluated once. Some older engines re-run it per row; the candidate should know how to hoist it or when the planner already does.)