MySQL GROUP_CONCAT() to PostgreSQL STRING_AGG() Crosswalk

PostgreSQL's STRING_AGG() does the same job as MySQL's GROUP_CONCAT(), but makes the separator mandatory and moves ORDER BY to a different position in the call.

Close equivalent Covers the common case, but has documented behavioral differences.

MySQL feature
GROUP_CONCAT()
PostgreSQL equivalent
STRING_AGG()

Main limitation: MySQL's GROUP_CONCAT() defaults to a comma separator when SEPARATOR is omitted; PostgreSQL's STRING_AGG() requires the separator as a mandatory second argument — omitting it is a syntax error, not an empty-string fallback.

Quick mapping

MySQL GROUP_CONCAT()
PostgreSQL STRING_AGG()

Examples

Concatenating grouped values with a separator

MySQL
SELECT department, GROUP_CONCAT(name SEPARATOR ', ') FROM employees GROUP BY department;
PostgreSQL
SELECT department, STRING_AGG(name, ', ') FROM employees GROUP BY department;
The separator is optional in MySQL (defaults to a comma) but mandatory in PostgreSQL.

Ordered concatenation

MySQL
SELECT GROUP_CONCAT(name ORDER BY name SEPARATOR ', ') FROM employees;
PostgreSQL
SELECT STRING_AGG(name, ', ' ORDER BY name) FROM employees;
ORDER BY moves from before SEPARATOR in MySQL to after the separator argument in PostgreSQL.

Caveats

Caveat

MySQL's GROUP_CONCAT() defaults to a comma separator when SEPARATOR is omitted; PostgreSQL's STRING_AGG() requires the separator as a mandatory second argument — omitting it is a syntax error, not an empty-string fallback.

Caveat

ORDER BY placement differs: MySQL writes it inside the call before SEPARATOR (GROUP_CONCAT(name ORDER BY name SEPARATOR ', ')); PostgreSQL writes it after the separator argument (STRING_AGG(name, ', ' ORDER BY name)).

Caveat

MySQL's GROUP_CONCAT() supports an inline DISTINCT keyword (GROUP_CONCAT(DISTINCT name)); PostgreSQL's STRING_AGG() has no DISTINCT keyword — pre-deduplicate with a subquery or a DISTINCT inner SELECT instead.

Caveat

MySQL silently truncates GROUP_CONCAT() output at the group_concat_max_len system variable (1024 bytes by default in many installs) unless raised; PostgreSQL's STRING_AGG() has no comparable length cap of its own.

References

  • MySQL Reference Manual — GROUP_CONCAT() (v8.4) — checked 2026-07-29
  • PostgreSQL docs — STRING_AGG (v17) — checked 2026-07-29

Last verified 2026-07-29.