N017-M4 Tier 2 · Core SQL · medium ecommerce · Brightlane

Return the product name and quantity for every order line item whose product is assigned to category `6`

Part of INNER JOIN in SQL

The problem

Brightlane's category team wants to audit order-line activity for a specific product grouping.

Write a query to return the product name and quantity for every order line item whose product is assigned to category 6.

Assumptions:

  • The order_items table contains one row per product per order.
  • The products table contains every product in the catalogue; category membership is recorded on products.category_id.
  • The category condition applies to the product record — order lines themselves carry no category information.

Output:

  • One row per qualifying line item, with columns product_name and quantity.
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,
  oi.quantity
FROM
  order_items oi
  JOIN products p ON oi.product_id = p.id
WHERE
  p.category_id = 6

The shape

The category_id lives on the product record, not on the order line. The join brings the product's category_id into scope on every line, and WHERE p.category_id = 6 then narrows the assembled rows to lines whose product belongs to that category.

Clause by clause

  • FROM order_items oi reads the line-items table. Each row here is one product on one order; the only product attribute it carries is product_id.
  • JOIN products p ON oi.product_id = p.id pairs each line with its product, attaching the full product record — name, price, category_id, everything — to the line.
  • WHERE p.category_id = 6 filters the assembled rows. The condition is on the product side because that's where category_id lives; the order line itself has no category attribute to filter on. Only lines whose product belongs to category 6 survive — the Crest Pro 14", Crest Air, Meridian T1 Carbon, and Volt XS 13 lines from the laptops category.
  • SELECT p.name AS product_name, oi.quantity returns the product name from the product side and the quantity from the line itself.

Why this and not filter order_items directly

The order line stores product_id but not category_id. There's no oi.category_id column to filter on, and the relationship between a product and its category is recorded once on the product record, not duplicated onto every line that sells that product. The only way to express "lines whose product is in category 6" is to join to products first, putting p.category_id in scope, and then filter on it.

This is the recurring pattern when the criterion lives one table away from the rows being reported. Join in the dimension that carries the attribute, then filter on the dimension. The fact table contributes the rows; the dimension contributes the filter column.

You practiced narrowing a fact table (line items) by an attribute that lives only on a related dimension (the product's category). The recurring shape any time the narrowing criterion isn't directly on the table being reported.

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.