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

Return three columns per order: the order ID, the high-value total, and the standard total

Part of Conditional Aggregation (CASE inside Aggregates) in SQL

The problem

Brightlane's pricing team wants to analyse each order's line items by price tier. Per order:

  • Total value of high-price line items (unit_price > $500).
  • Total value of standard line items (unit_price <= $500).

Line value is unit_price * quantity.

Write a query to return three columns per order: the order ID, the high-value total, and the standard total.

Assumptions:

  • The order_items table contains one row per product per order.
  • Each conditional total combines the per-line value (unit_price * quantity), not just unit_price.
  • The two tiers are mutually exclusive — every line item contributes to exactly one of the two columns.

Output:

  • One row per order with at least one line item, with columns order_id, high_value_total, and standard_total.
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
  order_id,
  SUM(
    CASE
      WHEN unit_price > 500 THEN unit_price * quantity
    END
  ) AS high_value_total,
  SUM(
    CASE
      WHEN unit_price <= 500 THEN unit_price * quantity
    END
  ) AS standard_total
FROM
  order_items
GROUP BY
  order_id

The shape

The value inside the THEN branch is unit_price * quantity — a per-line revenue calculation, not a stored column. SUM(CASE WHEN cond THEN unit_price * quantity END) computes that per-line value on the rows the predicate admits and totals them inside each order's group. Order 36 has a $1,999 high-value line and $498.99 of standard lines; order 71 has only standard lines, so the high-value column comes back as NULL.

Clause by clause

  • order_id is the grouping column; each order's line items form one group.
  • SUM(CASE WHEN unit_price > 500 THEN unit_price * quantity END) AS high_value_total checks each line's unit_price against the threshold. Lines above $500 contribute their per-line revenue (unit_price * quantity); lines at or below $500 fall through to NULL and SUM skips them.
  • SUM(CASE WHEN unit_price <= 500 THEN unit_price * quantity END) AS standard_total covers the complement. The <= is the boundary-inclusive operator — a line priced at exactly $500 lands in the standard bucket.
  • FROM order_items GROUP BY order_id partitions the rows per order before the aggregates run.

Why the computed value goes inside the THEN

The CASE branch can return any expression, not just a column reference. Computing unit_price * quantity inside THEN keeps the multiplication on the per-line input, then lets SUM total the per-line revenues across the group. Writing SUM(CASE WHEN cond THEN unit_price END) * SUM(CASE WHEN cond THEN quantity END) would multiply two group-level totals instead of summing the per-line products — a different number entirely.

The trap

The NULL results read as missing data, but they're a structural signal: that order has no line items in that bucket. A tier-mix report needs to read NULL as "zero lines at this tier," not "zero revenue at this tier." If the report needs zero-padding, adding ELSE 0 inside each CASE makes non-matched rows contribute zero and the totals come back as 0 instead of NULL.

You practiced SUM(CASE WHEN cond THEN expression END) where the value being summed is itself a calculation. The recurring shape: any per-line computed metric (revenue, weight, taxable amount) can be conditionally bucketed in the same one-pass aggregation.

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.