N020-H1 Tier 2 · Core SQL · hard ecommerce · Brightlane

Produces the cross-product of `products` and `categories` and then narrows it to the actual assignments

Part of CROSS JOIN in SQL

The problem

Brightlane's catalogue team is auditing category assignments. Starting from the full grid of every product paired with every category, the auditor wants to keep only the pairs where the product is actually assigned to that category.

Write a query that produces the cross-product of products and categories and then narrows it to the actual assignments.

Assumptions:

  • The match condition is products.category_id = categories.id. Applying this condition over the cross-product yields exactly the rows where each product is paired with its own category.
  • Products with an unresolved category_id and categories with no products do not appear in the result.

Output:

  • One row per actual assignment, with columns product_name and category_name.
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
  p.name AS product_name,
  c.name AS category_name
FROM
  products p
  CROSS JOIN categories c
WHERE
  p.category_id = c.id

The shape

The CROSS JOIN produces every possible product-category pairing first; the WHERE then keeps only the pairs where the product's category_id matches the category's id. What survives is one row per product paired with its own category — the actual assignments. This is what an INNER JOIN does under the hood, written out longhand.

Clause by clause

  • FROM products p CROSS JOIN categories c is the full cartesian product. If products has 25 rows and categories has 6, this intermediate result has 150 rows — every product paired with every category, regardless of relationship.
  • WHERE p.category_id = c.id is the match condition, applied as a filter on the cross-product. For each of the 150 pairs, PostgreSQL checks whether the product's recorded category ID equals the category's ID. Most pairs fail this check and drop out. Only the ones where the product is paired with its own category survive — one row per product.
  • p.name AS product_name and c.name AS category_name read from each surviving pair. The table aliases disambiguate the two name columns.

Why this and not INNER JOIN

SELECT ... FROM products p INNER JOIN categories c ON p.category_id = c.id returns the same rows. PostgreSQL is free to execute the two queries identically — the planner is smart enough to push the equality into the join itself rather than materialise the full cross-product. The result set is the same; the runtime is the same.

The value of writing it this way is conceptual. INNER JOIN ... ON is shorthand for "cross-product, then keep the rows where the condition holds." Every inner join is a cross-product filtered by its ON condition. Seeing the longhand once makes the shorthand legible — and makes accidental cross-products easier to spot, because you can recognise the row-explosion failure mode for what it is.

The trap

The trap is the inverse: forgetting the WHERE condition. SELECT ... FROM products p CROSS JOIN categories c with no filter returns all 150 rows — every product paired with every category, including 144 pairings that are wrong. The query runs, no error fires, and the audit ships with five wrong rows per product. Anywhere a cross-product is intended to become an inner join via a filter, the filter is mandatory; without it, the row count is the product of the table sizes and the result is meaningless.

You practiced expressing an INNER JOIN as a CROSS JOIN plus a WHERE condition on the matching key. The cross-product framing exposes what the INNER JOIN shorthand is doing underneath.

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.