N041-M1 Tier 3 · Intermediate · medium ecommerce · Brightlane

Return each high-activity customer's ID and order count

Part of Temp Tables and CREATE TABLE AS SELECT in SQL

The problem

Brightlane's analyst is building an intermediate dataset of high-activity customers — those with more than 3 orders on record — for a multi-step retention analysis. The dataset is materialized into a temp table once and then read by every downstream stage.

Write a query to return each high-activity customer's ID and order count.

Assumptions:

  • The orders table has one row per order with a customer_id.
  • A customer's order count is the number of orders linked to that customer_id.
  • Only customers whose order count is greater than 3 should appear.

Output:

  • One row per qualifying customer, with columns customer_id and order_count.
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
  customer_id,
  order_count
FROM
  (
    SELECT
      customer_id,
      COUNT(*) AS order_count
    FROM
      orders
    GROUP BY
      customer_id
  ) customer_stats
WHERE
  order_count > 3

The shape

Compute the per-customer order count in an inner step, then filter that result to keep only customers whose count exceeds 3. The inner aggregation has to finish before the threshold can be applied, because the threshold is a condition on order_count, a column that does not exist until the aggregation has run. A derived table is what gives the outer query something with that column to filter against.

Clause by clause

  • (SELECT customer_id, COUNT(*) AS order_count FROM orders GROUP BY customer_id) customer_stats is the inner derived table. It groups orders by customer_id, computes the per-customer order count, and exposes a two-column result that the outer query can treat exactly like a real table. The alias customer_stats names that result.
  • SELECT customer_id, order_count FROM customer_stats reads the derived table and returns both columns to the final result.
  • WHERE order_count > 3 filters the derived table to high-activity customers only. The filter runs after the aggregation, so order_count is a real value by the time the comparison runs. Customers whose count is 3 or below are dropped before the result is materialized.

Why this and not a WHERE on the raw orders table

WHERE runs before GROUP BY, on individual rows, before any aggregate has been computed. A condition like WHERE order_count > 3 written directly on orders would refer to a column that does not exist on the raw row. The aggregation has to happen first, the derived table exposes its result as a row source, and only then can WHERE apply a condition that compares against the aggregate.

You practiced computing a per-customer count and applying a threshold against it — the kind of restricted aggregate worth caching in a temp table when downstream reports reference it repeatedly.

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.