N028-H1 Tier 3 · Intermediate · hard analytics · Streamhub

Return each user's name and their plan status label

Part of COALESCE and NULLIF in SQL

The problem

Streamhub's admin team is building a plan status label for the user dashboard. The label varies by activity status and plan, with one display label reserved for inactive accounts.

Write a query to return each user's name and their plan status label.

Assumptions:

  • An inactive user (where is_active is FALSE) should always appear with the label 'Inactive' regardless of their plan.
  • Among active users, those with plan = 'free' should appear with the label 'Trial'.
  • All other active users should show their recorded plan.

Output:

  • One row per user, with columns name and plan_status.
Schema · analytics 5 tables
users
id integer
name text
email text
country text
plan text
signed_up_at timestamptz
is_active boolean
conversions
id integer
user_id integer
converted_at timestamptz
plan text
amount numeric
sessions
id integer
user_id integer
started_at timestamptz
ended_at? timestamptz
event_count integer
events
id integer
user_id integer
session_id? integer
event_type text
occurred_at timestamptz
properties? jsonb
periods
id integer
name text
start_month integer
end_month integer

Run previews · Check grades

Write a query, then run it to see results here.

Worked solution Try it yourself first
Solution query
SELECT
  name,
  CASE
    WHEN is_active = FALSE THEN 'Inactive'
    ELSE COALESCE(NULLIF(plan, 'free'), 'Trial')
  END AS plan_status
FROM
  users

The shape

The outer CASE splits users into two populations: inactive accounts get the label 'Inactive' outright, and active accounts run through the nested COALESCE(NULLIF(plan, 'free'), 'Trial') to derive their label from plan. Two independent decision dimensions, activity and plan, meet on the same output column without colliding, because each is handled in its own layer.

Clause by clause

  • SELECT name, CASE WHEN is_active = FALSE THEN 'Inactive' ELSE COALESCE(NULLIF(plan, 'free'), 'Trial') END AS plan_status returns each user's name and their plan status label. The CASE evaluates the activity test first: inactive users short-circuit straight to 'Inactive' and never touch the plan logic. Active users fall into the ELSE branch, where NULLIF(plan, 'free') rewrites 'free' to NULL and COALESCE(..., 'Trial') then rewrites that NULL to 'Trial'. Active users on any other plan have their plan returned unchanged.
  • FROM users reads every user. Both inactive accounts and free-plan active accounts stay in the result; they are exactly the rows the two label rewrites are for.

Why a CASE wrapping the nested expression and not a longer COALESCE chain

COALESCE and NULLIF only see the value of plan. They have no visibility into is_active, so the 'Inactive' label cannot be derived inside the nested expression at all. The inactive-versus-active split is a different dimension than the free-versus-paid split, and the only construct in scope that branches on an arbitrary boolean is CASE. CASE runs first, separates the two populations, and hands only the active rows to the nested label logic.

The trap

Reading the expression top to bottom hides that the CASE runs first and the nested rewrite runs only on the ELSE branch. A reader expecting the COALESCE to also fire on inactive rows would write the wrong label for any inactive user whose plan happens to be 'free'. The execution order is outside-in: the outer construct evaluates first, picks a branch, and only the chosen branch's expression runs at all.

You practiced nesting COALESCE(NULLIF(...)) inside a CASE — an outer category split sets one branch's label outright, while the other branch runs the nested sentinel rewrite.

How you actually get good at SQL

Reading explains SQL. Writing it, over and over with instant feedback, is what makes you fluent.

That's the whole SQLMaxx loop: 600+ real problems, instant AI feedback, mastery you can actually see, and spaced review that won't let you forget.

A stack of SQL practice problem cards, the top card showing an employees table.
615 problems · 66 concepts

Real problems. Not toy examples.

615 hand-built problems spanning all 66 concepts, from basic SELECTs to window functions, built on real schemas and real business questions, the kind you'll actually get asked on the job. Enough reps to make SQL automatic.

A retro computer showing a SQL query marked correct with a green checkmark.
Instant AI feedback

Write a query. Know if it's right in one second.

No copying an answer and hoping it clicked. The AI grader checks your real query against real data, catches exactly what's wrong, and explains the fix in plain English, like a senior analyst reading over your shoulder on every problem.

A circular mastery progress dial filling from blue to green, the SQLMaxx diamond at its center.
Mastery tracking

Stop guessing whether you actually know it.

SQLMaxx tracks every concept and shows you what you've mastered and what's still shaky. Your skills fill in one concept at a time, so 'I think I get joins' becomes something you can prove.

A SQL query editor circled by a blue return arrow with a clock, scheduled to come back for review.
Spaced review

Learn it once. Keep it for good.

Most of what you learn this week fades by next week. So when a concept comes due for review, SQLMaxx hands you a fresh problem to solve from a blank editor, not a flashcard to re-read. A research-backed spaced-repetition algorithm (FSRS) times each return for right before you'd forget, so your SQL is still there months later, when the interview or the job actually needs it.

Practice, feedback, mastery, review. That's the loop that turns reading into real skill.

Start free

No account, no credit card. Start solving in under a minute.