N030-M3 Tier 3 · Intermediate · medium ecommerce · Brightlane

Return the status, order count, and total revenue for every status whose combined order revenue exceeds `$5,000`

Part of Common Table Expressions (CTEs) in SQL

The problem

Brightlane's finance team is reviewing pipeline health by order status.

Write a query to return the status, order count, and total revenue for every status whose combined order revenue exceeds $5,000.

Assumptions:

  • The orders table has one row per order with a status and a total_amount.
  • A status's combined order revenue is the total of total_amount across every order in that status.
  • Only statuses whose combined revenue exceeds $5,000 should appear.

Output:

  • One row per qualifying status, with columns status, order_count, and total_revenue.
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
WITH
  status_revenue AS (
    SELECT
      status,
      COUNT(*) AS order_count,
      SUM(total_amount) AS total_revenue
    FROM
      orders
    GROUP BY
      status
  )
SELECT
  status,
  order_count,
  total_revenue
FROM
  status_revenue
WHERE
  total_revenue > 5000

The shape

One WITH layer computes both per-status figures at once. GROUP BY status partitions the rows, and COUNT(*) and SUM(total_amount) produce two aggregates side by side. The main query reads all three columns and applies the threshold against total_revenue.

Clause by clause

  • The WITH clause defines status_revenue:
WITH status_revenue AS (
  SELECT status, COUNT(*) AS order_count, SUM(total_amount) AS total_revenue
  FROM orders
  GROUP BY status
)

A single grouping pass produces both aggregates per status. The layer ends up with one row per status carrying its count and its revenue total: 'delivered' shows 161 orders and $104,331.81; 'shipped' shows 17 orders and $10,954.98; the other statuses follow the same shape.

  • SELECT status, order_count, total_revenue FROM status_revenue WHERE total_revenue > 5000 is the main query. It reads the layer and keeps only the rows where revenue exceeds 5000. Every status on this data clears the threshold, since the smallest total_revenue is 5290.98 on 'pending'.

Why one layer with both aggregates, not two

A single GROUP BY status scan can carry as many aggregate expressions as you list in the SELECT. Computing COUNT(*) and SUM(total_amount) in the same layer reads the table once and produces both columns. Splitting them into two layers would force two separate aggregations over the same row partitions, which is the same work duplicated. Two aggregates over the same grouping go in the same layer.

The trap

The threshold runs against total_revenue, not order_count. The two aggregates land side by side in the layer's output, which makes it easy to filter on the wrong one by reflex. WHERE order_count > 5000 would silently return a different population, since order_count is a count of orders and total_revenue is a sum of dollars. Naming each aggregate clearly with AS is what makes the filter readable; the names in the main query's WHERE have to match the intent of the threshold.

You practiced computing two per-category figures in one WITH layer and applying a threshold against one of them in the main query.

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.