N048-E2 Tier 4 · Advanced · easy ecommerce · Brightlane

Return one row per order line item, showing the order ID, customer ID, product ID, and unit price for that item

Part of LATERAL Joins in SQL

The problem

Brightlane's fulfillment operations team is conducting a line-item audit and needs every product included in every order.

Write a query to return one row per order line item, showing the order ID, customer ID, product ID, and unit price for that item.

Assumptions:

  • An order with multiple line items contributes one output row per line item.
  • Orders with no line items on record do not appear in the result.

Output:

  • One row per order line item, with columns order_id, customer_id, product_id, and unit_price.
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
  o.id AS order_id,
  o.customer_id,
  items.product_id,
  items.unit_price
FROM
  orders o
  CROSS JOIN LATERAL (
    SELECT
      product_id,
      unit_price
    FROM
      order_items oi
    WHERE
      oi.order_id = o.id
  ) items

The shape

The lateral subquery sees o.id from the outer order row and pulls back every line item linked to that order. Because the lateral returns one row per line item, the outer order row is duplicated once per item, which is exactly the per-line-item shape the audit asks for.

Clause by clause

  • SELECT o.id AS order_id, o.customer_id, items.product_id, items.unit_price returns the order's id and customer from the outer table, and the line item's product and unit price from the lateral.
  • FROM orders o is the driving table; the lateral will be evaluated once for each order row.
  • CROSS JOIN LATERAL ( SELECT product_id, unit_price FROM order_items oi WHERE oi.order_id = o.id ) items runs once per order and returns every matching line item. An order with three items contributes three output rows; an order with no items returns zero rows from the lateral. CROSS JOIN then drops that outer order, which matches the prompt's rule that orders with no line items do not appear.

Why this and not a plain inner join

FROM orders o INNER JOIN order_items oi ON oi.order_id = o.id returns the same rows on this data, and on a flat per-line-item audit either form is correct. The lateral version generalises better. The moment the inner query needs an aggregate, an ORDER BY ... LIMIT per order, or a GROUP BY over each order's items, the inner join cannot express it without a derived table; the lateral already has the shape that supports any of those extensions. Reading this query as "for each order, get its line items" mirrors the audit's question more directly than a flat join.

You practiced CROSS JOIN LATERAL returning multiple rows per outer record — each parent record pairs with as many lateral rows as the inner query produces; parents with zero matches are dropped.

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.