PostgreSQL 9.0 ou posterior:
Versões recentes do Postgres (desde o final de 2010) têm a string_agg(expression, delimiter)
função que fará exatamente o que a pergunta pediu, até mesmo permitindo que você especifique a string delimitadora:
SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;
O Postgres 9.0 também adicionou a capacidade de especificar uma ORDER BY
cláusula em qualquer expressão agregada ; caso contrário, o pedido não será definido. Agora você pode escrever:
SELECT company_id, string_agg(employee, ', ' ORDER BY employee)
FROM mytable
GROUP BY company_id;
Ou de fato:
SELECT string_agg(actor_name, ', ' ORDER BY first_appearance)
PostgreSQL 8.4 ou posterior:
O PostgreSQL 8.4 (em 2009) introduziu a função agregadaarray_agg(expression)
que concatena os valores em uma matriz. Então array_to_string()
pode ser usado para dar o resultado desejado:
SELECT company_id, array_to_string(array_agg(employee), ', ')
FROM mytable
GROUP BY company_id;
string_agg
para versões anteriores à 8.4:
Caso alguém se depare com isso procurando uma correção de compatibilidade para bancos de dados anteriores à 9.0, é possível implementar tudo, string_agg
exceto a ORDER BY
cláusula.
Portanto, com a definição abaixo, isso deve funcionar da mesma maneira que no DB 9.x do Postgres:
SELECT string_agg(name, '; ') AS semi_colon_separated_names FROM things;
Mas este será um erro de sintaxe:
SELECT string_agg(name, '; ' ORDER BY name) AS semi_colon_separated_names FROM things;
--> ERROR: syntax error at or near "ORDER"
Testado no PostgreSQL 8.3.
CREATE FUNCTION string_agg_transfn(text, text, text)
RETURNS text AS
$$
BEGIN
IF $1 IS NULL THEN
RETURN $2;
ELSE
RETURN $1 || $3 || $2;
END IF;
END;
$$
LANGUAGE plpgsql IMMUTABLE
COST 1;
CREATE AGGREGATE string_agg(text, text) (
SFUNC=string_agg_transfn,
STYPE=text
);
Variações personalizadas (todas as versões do Postgres)
Antes da 9.0, não havia função agregada incorporada para concatenar seqüências de caracteres. A implementação personalizada mais simples ( sugerida por Vajda Gabo nesta postagem da lista de discussão , entre muitas outras) é usar a textcat
função interna (que fica atrás do ||
operador):
CREATE AGGREGATE textcat_all(
basetype = text,
sfunc = textcat,
stype = text,
initcond = ''
);
Aqui está a CREATE AGGREGATE
documentação.
Isso simplesmente cola todas as cordas, sem separador. Para obter um "," inserido entre eles sem tê-lo no final, convém criar sua própria função de concatenação e substituí-la pelo "textcat" acima. Aqui está um que eu montei e testei em 8.3.12:
CREATE FUNCTION commacat(acc text, instr text) RETURNS text AS $$
BEGIN
IF acc IS NULL OR acc = '' THEN
RETURN instr;
ELSE
RETURN acc || ', ' || instr;
END IF;
END;
$$ LANGUAGE plpgsql;
Esta versão produzirá uma vírgula mesmo que o valor na linha seja nulo ou vazio, para que você obtenha uma saída como esta:
a, b, c, , e, , g
Se você preferir remover vírgulas extras para gerar isso:
a, b, c, e, g
Em seguida, adicione uma ELSIF
verificação à função como esta:
CREATE FUNCTION commacat_ignore_nulls(acc text, instr text) RETURNS text AS $$
BEGIN
IF acc IS NULL OR acc = '' THEN
RETURN instr;
ELSIF instr IS NULL OR instr = '' THEN
RETURN acc;
ELSE
RETURN acc || ', ' || instr;
END IF;
END;
$$ LANGUAGE plpgsql;