array_agg (in array context)
PG 8.4+→ anyarraySee aggregate category. In array context: re-aggregates unnested elements back into arrays.
Signature
array_agg ( expression ) → anyarrayParameters
| Parameter | Type | Description |
|---|---|---|
| expression | any | Value to aggregate into array |
Examples
Deduplicate and sort array
SELECT array_agg(DISTINCT x ORDER BY x) FROM unnest(ARRAY[3,1,2,1]) AS x;{1,2,3}SELECT array_agg(x) FILTER (WHERE x > 2) FROM unnest(ARRAY[1,2,3,4]) AS x;{3,4}SELECT post_id, array_agg(tag ORDER BY tag) AS sorted_tags FROM post_tags GROUP BY post_id;Alphabetically sorted tag array per postSELECT user_id, array_agg(order_id ORDER BY created_at DESC) AS recent_orders FROM orders GROUP BY user_id;Per-user array of order IDs sorted newest-first`array_agg` without an explicit `ORDER BY` clause returns elements in an indeterminate order — PostgreSQL makes no guarantee about the sequence. Any code that relies on positional array access (e.g., `arr[1]`) after an unordered `array_agg` is fragile and can produce different results across runs or plan changes.
✓ Instead: SELECT array_agg(item ORDER BY sort_key) FROM t GROUP BY group_col;
To remove duplicates from an array: `(SELECT array_agg(DISTINCT x) FROM unnest(arr) AS x)` or use `array(SELECT DISTINCT unnest(arr) ORDER BY 1)`.
SELECT array(SELECT DISTINCT unnest(tags) ORDER BY 1) AS unique_sorted_tags FROM posts;Sorted, deduplicated tag arrayCommon Gotchas
string_agg without ORDER BY produces non-deterministic results
string_agg(col, ',') returns results in arbitrary order unless you specify ORDER BY inside the aggregate.
COUNT(col) skips NULLs but COUNT(*) does not
COUNT(column_name) counts non-NULL values only. COUNT(*) counts all rows. These produce different results when the column has NULLs.
Arrays are 1-indexed in PostgreSQL, not 0-indexed
PostgreSQL arrays start at index 1 by default. array[0] returns NULL, not the first element — silently wrong.