Brightlane's order processing team needs a line-item summary per order showing the product IDs that were included as a comma-separated text string.
Write a query to return every order ID and its product IDs as a comma-separated string, with the IDs arranged in ascending numeric order.
Assumptions:
- The
order_itemstable has one row per line item with anorder_idand aproduct_id. - Each
order_idwith at least one line item should appear once. - For each order, the product-IDs list contains every
product_idvalue of items in that order (one entry per line item, no de-duplication), with the IDs sorted numerically (not lexically) before being assembled with', 'between adjacent values.
Output:
- One row per order with at least one line item, with columns
order_idandproduct_ids.
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
order_id,
STRING_AGG(
product_id::TEXT,
', '
ORDER BY
product_id
) AS product_ids
FROM
order_items
GROUP BY
order_id The shape
STRING_AGG(product_id::text, ', ' ORDER BY product_id) joins each order's product IDs into a single text value, with the IDs sorted by their numeric value before they are concatenated. The ::text cast handles the type requirement of STRING_AGG without changing the sort order, because the ORDER BY is evaluated against the original numeric column.
Clause by clause
SELECT order_id, STRING_AGG(product_id::text, ', ' ORDER BY product_id) AS product_idsreturns the order ID alongside the concatenated product-ID list.STRING_AGGrequires its first argument to be text, which is whyproduct_id::textconverts the integer column into text values the aggregate can join. TheORDER BY product_idreferences the original integer column, so the sequence is14, 22, 32— numeric order — not the lexical order a text sort would give (14, 22, 32happens to match here, but on IDs like2, 11, 100a text sort would produce100, 11, 2instead). The', 'literal sits between adjacent values.FROM order_itemsreads the line-item rows. Every line item contributes to its order's list.GROUP BY order_idpartitions the rows by order so the aggregate runs once per order. One output row per distinctorder_id.
Why this and not STRING_AGG(product_id::text, ', ' ORDER BY product_id::text)
Both compile, but they produce different results once IDs cross digit-length boundaries. Sorting by the cast text orders the values lexically: '100' sorts before '11' because '0' comes before '1' character by character. Sorting by the underlying product_id orders them numerically, which is what the prompt asks for. Cast for concatenation, sort against the typed source.
You practiced STRING_AGG(column::text, separator ORDER BY column) — cast a numeric column to text for concatenation while keeping the numeric ordering intact.