MySQL
SQL functions
GROUP_CONCAT
CONCAT
database queries

How to use GROUP_CONCAT in a CONCAT in MySQL

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

GROUP_CONCAT and CONCAT solve different problems but combine well. GROUP_CONCAT aggregates values from multiple rows into one string per group, while CONCAT lets you wrap that aggregated result with labels, prefixes, suffixes, or other column values.

Understand The Difference First

CONCAT works within one output row:

sql
SELECT CONCAT('Order-', 42) AS value;

GROUP_CONCAT works across several rows in the same group:

sql
SELECT customer_id, GROUP_CONCAT(product_name)
FROM orders
GROUP BY customer_id;

If you want a sentence-like summary per customer, you usually nest GROUP_CONCAT inside CONCAT.

A Basic Nested Example

Suppose the table is:

sql
1CREATE TABLE orders (
2  customer_id INT,
3  product_name VARCHAR(50)
4);

Then:

sql
1SELECT
2  customer_id,
3  CONCAT(
4    'Customer ',
5    customer_id,
6    ' bought: ',
7    GROUP_CONCAT(product_name ORDER BY product_name SEPARATOR ', ')
8  ) AS summary
9FROM orders
10GROUP BY customer_id;

This creates one readable string per customer by combining row aggregation and row-level string formatting.

The normal pattern is:

  1. aggregate with GROUP_CONCAT
  2. decorate with CONCAT

Handle NULL Carefully

This is where many queries go wrong.

GROUP_CONCAT ignores NULL values in the grouped column, but CONCAT returns NULL if any argument is NULL.

That means COALESCE is often necessary:

sql
1SELECT
2  customer_id,
3  CONCAT(
4    'Items: ',
5    COALESCE(GROUP_CONCAT(product_name SEPARATOR ', '), 'none')
6  ) AS summary
7FROM orders
8GROUP BY customer_id;

If the aggregate result would otherwise be NULL, COALESCE keeps the whole summary string usable.

CONCAT_WS can also help because it skips NULL arguments more gracefully than plain CONCAT.

Ordering And Length Limits Matter

If order matters, specify it inside GROUP_CONCAT:

sql
GROUP_CONCAT(product_name ORDER BY product_name SEPARATOR ', ')

Otherwise the order is not guaranteed to be stable.

Also remember the result can be truncated by group_concat_max_len:

sql
SHOW VARIABLES LIKE 'group_concat_max_len';
SET SESSION group_concat_max_len = 100000;

This becomes important when you aggregate many rows or long strings.

Use Grouping Rules Explicitly

If you include other columns in the result, make sure the grouping remains valid:

sql
1SELECT
2  c.customer_id,
3  CONCAT(
4    c.customer_name,
5    ' ordered ',
6    GROUP_CONCAT(o.product_name ORDER BY o.product_name SEPARATOR ', ')
7  ) AS summary
8FROM customers AS c
9JOIN orders AS o ON o.customer_id = c.customer_id
10GROUP BY c.customer_id, c.customer_name;

That keeps the query portable and predictable under stricter SQL modes.

In reporting queries, this pattern is often used to build labels, compact summaries, or export-friendly text columns. It is convenient, but it is still string formatting layered on top of grouped data, so avoid treating the result like structured relational data later in the same workflow.

CONCAT_WS Is Often Cleaner

If some pieces may be NULL, CONCAT_WS can reduce manual null handling:

sql
1SELECT
2  customer_id,
3  CONCAT_WS(
4    ' ',
5    'Items:',
6    GROUP_CONCAT(product_name ORDER BY product_name SEPARATOR ', ')
7  ) AS summary
8FROM orders
9GROUP BY customer_id;

Because CONCAT_WS skips NULL arguments, it is often more forgiving than plain CONCAT when optional pieces of the message may be missing.

Common Pitfalls

One common mistake is forgetting the GROUP BY, even though GROUP_CONCAT is an aggregate.

Another issue is not realizing that CONCAT turns the entire result to NULL if one argument is NULL.

A third problem is forgetting to add ORDER BY inside GROUP_CONCAT, which leads to unstable-looking summaries.

Finally, large grouped strings may be silently truncated if group_concat_max_len is too small.

Summary

  • Use GROUP_CONCAT to aggregate many row values into one string per group.
  • Wrap it in CONCAT when you want labels or sentence-style output.
  • Use COALESCE or CONCAT_WS to avoid NULL surprises.
  • Specify ORDER BY inside GROUP_CONCAT when output order matters.
  • Check group_concat_max_len if long aggregated strings seem incomplete.
  • Format aggregated output consciously so downstream code does not need to guess.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.