N050-H1 Tier 4 · Advanced · hard ecommerce · Brightlane

Return every customer ID and a comma-separated list of order statuses arranged in ascending order of `total_amount` within that customer's history. Sort the final result by `customer_id` ascending

Part of STRING_AGG and ARRAY_AGG in SQL

The problem

Brightlane's customer service team wants every customer's order history as a sequence of statuses ordered by purchase value within each customer — smallest amount first, largest last. The customer rows themselves should be sorted by ID.

Write a query to return every customer ID and a comma-separated list of order statuses arranged in ascending order of total_amount within that customer's history. Sort the final result by customer_id ascending.

Assumptions:

  • Each customer_id with at least one order should appear once.
  • For each customer, the statuses list contains every order's status value (one entry per order, no de-duplication), arranged by ascending total_amount within the list, separated by ', '.
  • The final result is sorted by customer_id ascending.

Output:

  • One row per customer with at least one order, with columns customer_id and statuses_by_amount. Sorted by customer_id ascending.
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,
  STRING_AGG(
    status,
    ', '
    ORDER BY
      total_amount
  ) AS statuses_by_amount
FROM
  orders
GROUP BY
  customer_id
ORDER BY
  customer_id

The shape

Two independent orderings sit in the same query and do not interfere with each other. STRING_AGG(status, ', ' ORDER BY total_amount) controls the sequence of statuses inside one customer's value: smallest order first, largest last. The query-level ORDER BY customer_id controls which customer row prints before which. Both are required, and each refuses to do the other one's job.

Clause by clause

  • SELECT customer_id, STRING_AGG(status, ', ' ORDER BY total_amount) AS statuses_by_amount returns the customer's ID and the per-customer status list. The status values are concatenated with ', ' between them; the ORDER BY total_amount inside the aggregate orders the contributing rows by purchase value before the join happens, so a customer whose orders are ($50, delivered), ($200, cancelled), ($90, shipped) produces 'delivered, shipped, cancelled' (sorted by amount, status carried along).
  • FROM orders reads the order rows. Every order is in scope.
  • GROUP BY customer_id partitions the rows by customer so the aggregate runs once per customer. One output row per distinct customer_id.
  • ORDER BY customer_id sorts the printed result set so customer 1 prints before customer 2. This is a separate clause from the aggregate's internal ORDER BY; it acts on the rows produced by GROUP BY, not on the rows feeding the aggregate.

The trap

Conflating the two ORDER BY positions silently produces the wrong answer. Writing ORDER BY total_amount at the query level instead of inside the aggregate would try to sort the printed result by an amount, but total_amount is not a grouping key and is not selected, so the query fails outright. Writing ORDER BY customer_id inside the aggregate would compile, but it would order the contributing rows by their customer_id — which is the same value for every row in the group, so the resulting sequence would be the table's physical order, not the amount order the prompt asks for. The rule is positional: the aggregate's ORDER BY shapes the value, the query's ORDER BY shapes the result set. They are not interchangeable.

You practiced two independent orderings in one query — STRING_AGG(... ORDER BY total_amount) controls the sequence inside each cell; the query-level ORDER BY customer_id controls which row appears first in the result.

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.