Skip to content
/Chapter 16 · Summary Reports & Pivots
Lesson 16.3·garden_shop
Lesson 16.3

Listing Group Values with STRING_AGG in SQL

Sometimes a report needs the members of each group, not just a count. STRING_AGG rolls them into one readable cell.

Most aggregates reduce a group to a number. string_agg is different: it concatenates a column's values across the group into a single string, joined by a separator you choose. It's perfect for a "who / what's in this group" column.

Add order by inside the aggregate so the list is stable and readable. Without it, the order of the concatenated values isn't guaranteed.

Pattern
select order_id,
       string_agg(product_name, ', ' order by product_name) as items
from order_lines
group by order_id

The function name varies by database: it's string_agg in DuckDB, Postgres, and SQL Server, group_concat in MySQL and SQLite, and listagg in Oracle, but the idea is the same.

Schema · Garden ShopTable · products9 columns · 24 rows
Table · products

One row per product, with price, cost, and inventory levels.

9 columns · 24 rows
product_id intproduct_name textcategory_id intsupplier_id intprice decimalcost decimalquantity_on_hand intreorder_level intdiscontinued bool
Your task

For each category, return category_name, the count ofproducts, and a product_list: every product name in that category, in alphabetical order, joined by ", ". Order the rows by category name.

SQL Workbench
query.sqlgarden_shop · SQL engine loading
⌘↵ to run
·
Expected answer
  • Columns: category_name, products, product_list.
  • Rows: one per category (8 rows).
  • product_list holds every product name in the category, comma-separated and alphabetical.