CMD Guide
HomeDatabasesSQL Practice Problems

Customer Purchase Summary

A GROUP BY customer_id collapses every purchase row for one customer into a single output row, and the aggregate functions run over the set of grouped rowsCOUNT(DISTINCT product) deduplicates while it counts, and GROUP_CONCAT(DISTINCT product ORDER BY product SEPARATOR ',') deduplicates, sorts, and stitches the surviving values into one comma-joined string, all inside the same grouping pass.

The problem

Given a purchases table where a customer can buy the same product more than once, produce one row per customer showing how many distinct products they bought and an alphabetised, comma-separated list of those product names.

-- purchases
 purchase_id | customer_id | product
-------------+-------------+----------
      1      |     101     | Mouse
      2      |     101     | Keyboard
      3      |     101     | Mouse      -- repeat
      4      |     102     | Monitor
      5      |     101     | Webcam
      6      |     102     | Monitor    -- repeat

The query (MySQL)

SELECT
    customer_id,
    COUNT(DISTINCT product) AS distinct_products,
    GROUP_CONCAT(DISTINCT product ORDER BY product SEPARATOR ',') AS product_list
FROM purchases
GROUP BY customer_id
ORDER BY customer_id;

The two aggregates are independent passes over the same group: one returns a number, the other returns a string. The DISTINCT, ORDER BY, and SEPARATOR clauses all live inside the GROUP_CONCAT parentheses — they shape that one aggregate's input, not the outer query.

Step-by-step trace for customer 101

Customer 101 has four purchase rows: Mouse, Keyboard, Mouse, Webcam. Watch what each clause does to that multiset, in order.

StepClauseWorking set for 101
1Group's raw values[Mouse, Keyboard, Mouse, Webcam]
2DISTINCT — drop duplicate Mouse{Keyboard, Mouse, Webcam}
3ORDER BY product — sort alphabetically[Keyboard, Mouse, Webcam]
4SEPARATOR ',' — join'Keyboard,Mouse,Webcam'

In parallel, COUNT(DISTINCT product) sees the same step-2 set {Keyboard, Mouse, Webcam} and returns 3 — not 4, because the duplicate Mouse was collapsed before counting.

diagram
diagram

Full output

Customer 102 bought Monitor twice; DISTINCT collapses it to one, so the count is 1 and the list is the single value.

customer_iddistinct_productsproduct_list
1013Keyboard,Mouse,Webcam
1021Monitor

Why the naive version is wrong

The instinctive write is COUNT(product) and a bare GROUP_CONCAT(product). Both fail on real data:

Portability: this is MySQL-specific

That DISTINCT ... ORDER BY ... SEPARATOR form is MySQL/MariaDB syntax. The standard-SQL equivalent (PostgreSQL, modern SQL Server, Oracle) is STRING_AGG, and its grammar differs:

-- PostgreSQL
SELECT
    customer_id,
    COUNT(DISTINCT product) AS distinct_products,
    STRING_AGG(DISTINCT product, ',' ORDER BY product) AS product_list
FROM purchases
GROUP BY customer_id
ORDER BY customer_id;

The separator is a positional argument, not a SEPARATOR keyword. PostgreSQL allows DISTINCT together with ORDER BY only when the ORDER BY expression matches the aggregated expression — order by product while aggregating product is fine; order by some other column would raise "in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list". SQL Server's STRING_AGG uses WITHIN GROUP (ORDER BY product) and has no DISTINCT support at all — you must pre-deduplicate in a subquery or CTE.

Pitfalls

Takeaways


Re-authored and deepened for this guide. Mechanism and clause-ordering semantics verified against the MySQL 8.0 Reference Manual (12.20 Aggregate Functions, GROUP_CONCAT and group_concat_max_len), the PostgreSQL 16 documentation (9.21 Aggregate Functions, STRING_AGG with DISTINCT/ORDER BY constraints), and the Microsoft SQL Server STRING_AGG / WITHIN GROUP reference. Worked example and failure modes authored for this page.

🤖 Don't fully get this? Learn it with Claude

Stuck on Customer Purchase Summary? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Customer Purchase Summary** (Databases) and want to truly understand it. Explain Customer Purchase Summary from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Customer Purchase Summary** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Customer Purchase Summary** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Customer Purchase Summary** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes