N010-H1 Tier 1 · Foundations · hard ecommerce · Brightlane

Return one row per unique city value

Part of DISTINCT in SQL

The problem

A shipping system at Brightlane is building a city dropdown for address validation. The dropdown needs every city value that appears in the customer base, with a single entry representing customers who have no city on file.

Write a query to return one row per unique city value.

Assumptions:

  • The customers table contains every customer Brightlane has on file.
  • Some customers have a recorded city value; many customers have a missing city.
  • Customers with no city on file appear as a single row in the dropdown — one entry, not one per missing-city customer.

Output:

  • One row per unique city value, with a single column city. One row will have a missing city.
Schema · ecommerce 5 tables
categories
id integer
name text
parent_id? integer
products
id integer
name text
category_id integer
price numeric
stock_qty integer
attributes? jsonb
order_items
id integer
order_id integer
product_id integer
quantity integer
unit_price numeric
customers
id integer
name text
email text
city? text
country text
created_at timestamptz
is_active boolean
orders
id integer
customer_id integer
ordered_at timestamptz
status text
total_amount numeric

Run previews · Check grades

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

Worked solution Try it yourself first
Solution query
SELECT DISTINCT
  city
FROM
  customers

The shape

DISTINCT treats two NULL values as equal for the purpose of deduplication, even though NULL = NULL is unknown everywhere else in SQL. That's the entire reason this query works as a single statement. Hundreds of customers with no city on file collapse into one NULL row in the dropdown, alongside every real city.

Clause by clause

  • SELECT DISTINCT city returns the unique city values from whatever rows FROM hands up. The deduplication runs across the full candidate set, and a NULL row collapses against any other NULL row the same way two London rows would collapse.
  • FROM customers is the row source. Every customer contributes their city value — including the missing ones — to the candidate set. There's no filter; the dropdown wants the missing case represented, not removed.

Why this and not a two-statement approach

The natural-feeling instinct is to think of NULL handling as a separate concern: deduplicate the real cities, then add a row for the missing case. That instinct comes from how NULL equality usually works in SQL, where two NULLs are never equal to each other. If DISTINCT followed those rules, every NULL row would survive deduplication as its own distinct value, and the dropdown would contain hundreds of empty rows.

DISTINCT doesn't follow those rules. The SQL standard makes a deliberate exception for deduplication contexts: two NULLs are equal for the purpose of removing duplicates. So the single SELECT DISTINCT city FROM customers produces exactly the dropdown shape the address-validation system needs — one row per real city plus one row representing the missing case.

You practiced relying on DISTINCT's NULL-as-equal behavior. The recurring shape any time a deduplicated result must surface a single 'missing' row alongside the real values.

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.