Brightlane's finance team wants to identify customers who have placed high-value orders, along with how many such orders each customer has on record.
Write a query to return each qualifying customer's ID and their count of high-value orders.
Assumptions:
- A high-value order has
total_amountgreater than$500. - A customer's high-value-order count is the number of high-value orders linked to that
customer_id. - Only customers with at least one high-value order should appear.
Output:
- One row per qualifying customer, with columns
customer_idandbig_order_count.
Schema · ecommerce 5 tables
Run previews · Check grades
Write a query, then run it to see results here.
Worked solution Try it yourself first
WITH
big_orders AS (
SELECT
customer_id,
total_amount
FROM
orders
WHERE
total_amount > 500
),
customer_counts AS (
SELECT
customer_id,
COUNT(*) AS big_order_count
FROM
big_orders
GROUP BY
customer_id
)
SELECT
customer_id,
big_order_count
FROM
customer_counts The shape
Restrict first, then aggregate. The first CTE keeps only the high-value orders, and the second counts those qualifying rows per customer. Because the count runs over the already-filtered set, every counted row is by definition a big order and no row needs to be discounted at aggregation time.
Clause by clause
The first CTE drops every order below the threshold:
WITH big_orders AS (
SELECT customer_id, total_amount
FROM orders
WHERE total_amount > 500
)WHERE total_amount > 500 filters the orders before any grouping happens. The SELECT list carries customer_id forward because the next layer needs it as the grouping key, and total_amount could be dropped here but is harmless to keep.
The second CTE groups the qualifying orders by customer:
customer_counts AS (
SELECT customer_id, COUNT(*) AS big_order_count
FROM big_orders
GROUP BY customer_id
)FROM big_orders reads only the orders that survived the filter. GROUP BY customer_id produces one row per customer, and COUNT(*) counts the high-value orders in each group. Customers with zero big orders never appear in big_orders and therefore never appear in this layer either, which is the "at least one" requirement satisfied implicitly.
SELECT customer_id, big_order_count FROM customer_countsreturns the final per-customer counts.
Why restrict in the first CTE instead of restricting after the aggregation
Moving the threshold up front is what makes "at least one high-value order" automatic. A customer with no qualifying orders contributes no rows to big_orders and therefore no row to customer_counts. If the filter were skipped and the count were computed first across all orders, the threshold would have to come back as a separate condition on the count, and the count itself would be "all orders" rather than "high-value orders." The order of operations changes what is being counted, not just how the answer is filtered. Restricting first is what makes the count a count of high-value orders.
You practiced layering two WITH stages — pre-restrict the source records in the first stage, then compute a per-customer count over only the qualifying records in the second.