Existe um string_agg() embutido que faz o que você quer, mas você pede especificamente que seja nomeado group_concat para compatibilidade com MySQL. Infelizmente, string_agg() usa um tipo de dados interno para acumulação (presumivelmente para evitar copiar todo o buffer em cada anexo, mas não olhei a fonte) e não encontrei uma maneira de declarar um agregado SQL idêntico a string_agg( ).
Definir a função group_concat() também não funcionaria, pois pg deve estar ciente de que é uma agregação, não uma função com uma agregação oculta dentro, o que não funcionaria. Tal função operaria em uma linha de cada vez:qualquer agregação dentro agregaria apenas uma única linha e a retornaria inalterada ...
Assim, este código irá acumular os elementos em um array, então adicionar os delimitadores "," com array_to_string. Usarei a declaração array_agg() (antes de se tornar um built-in) como modelo e simplesmente adicionarei uma função finalizadora que converterá a matriz agregada em texto.
CREATE OR REPLACE FUNCTION _group_concat_finalize(anyarray)
RETURNS text AS $$
SELECT array_to_string($1,',')
$$ IMMUTABLE LANGUAGE SQL;
CREATE AGGREGATE group_concat(anyelement) (
SFUNC=array_append,
STYPE=anyarray,
FFUNC=_group_concat_finalize,
INITCOND='{}'
);
SELECT group_concat(x) FROM foo;
O bom é que deve funcionar bem para qualquer tipo, sem problemas, graças aos tipos genéricos "anyarray" e "anyelement".
Eu presumo que isso seria mais lento que string_agg() se string_agg realmente evitar copiar toda a matriz de agregação em cada anexo. Isso deve importar apenas se o número de linhas a serem agrupadas em cada conjunto for grande. Nesse caso, você provavelmente pode gastar um minuto editando a consulta SQL;)
http://sqlfiddle.com/#!17/c452d/1