Brightlane's sales team is building a customer performance dashboard.
Write a query to return every customer ID, their total order count, the number of delivered orders, and the total revenue from delivered orders only.
Assumptions:
- The
orderstable has one row per order with acustomer_id, astatus, and atotal_amount. - Each
customer_idwith at least one order should appear once. - For each customer, the total count covers every order linked to that
customer_id. The delivered count covers only orders withstatus = 'delivered', and the delivered revenue is the combinedtotal_amountacross those delivered orders.
Output:
- One row per customer with at least one order, with columns
customer_id,total_orders,delivered_count, anddelivered_revenue.
Schema · ecommerce 5 tables
Run previews · Check grades
Write a query, then run it to see results here.
Worked solution Try it yourself first
SELECT
customer_id,
COUNT(*) AS total_orders,
COUNT(*) FILTER (
WHERE
status = 'delivered'
) AS delivered_count,
SUM(total_amount) FILTER (
WHERE
status = 'delivered'
) AS delivered_revenue
FROM
orders
GROUP BY
customer_id The shape
The same FILTER (WHERE status = 'delivered') condition attaches to two different aggregates inside one SELECT list. COUNT and SUM each restrict to the same delivered subset, but compute different statistics over it — and they coexist with the unfiltered COUNT(*) covering every order, all in one GROUP BY pass.
Clause by clause
SELECT customer_id, COUNT(*) AS total_orders, COUNT(*) FILTER (WHERE status = 'delivered') AS delivered_count, SUM(total_amount) FILTER (WHERE status = 'delivered') AS delivered_revenuereturns each customer's total order count, their count of delivered orders, and the combinedtotal_amountacross those delivered orders. The firstCOUNT(*)runs over every row in the partition; the next two aggregates run only over the partition's delivered rows. A customer with zero delivered orders gets a delivered count of0and a delivered revenue of NULL — becauseSUMover zero rows is NULL, the same waySUMis NULL for any empty input.FROM ordersreads the order records.GROUP BY customer_idpartitions the rows per customer. The three aggregates evaluate inside each customer's partition independently.
Why repeat the same FILTER on two aggregates instead of pre-filtering with WHERE
A WHERE status = 'delivered' would drop non-delivered rows before aggregation, which would also drop them from the COUNT(*) covering every order. The dashboard needs the total across every status alongside the delivered subset, in the same row. FILTER is the only construct in scope that restricts individual aggregates without restricting the whole partition. The duplication on the FILTER clauses is the price of keeping the unfiltered total honest.
You practiced FILTER on SUM as well as COUNT — the same condition restricts two different aggregates to the same delivered subset within each partition.