PostgreSQL 9.0 o posterior:
Las versiones recientes de Postgres (desde finales de 2010) tienen la string_agg(expression, delimiter)
función que hará exactamente lo que pedía la pregunta, incluso permitiéndole especificar la cadena delimitador:
SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;
Postgres 9.0 también agregó la capacidad de especificar una ORDER BY
cláusula en cualquier expresión agregada ; de lo contrario, el orden no está definido. Entonces ahora puedes escribir:
SELECT company_id, string_agg(employee, ', ' ORDER BY employee)
FROM mytable
GROUP BY company_id;
O de hecho:
SELECT string_agg(actor_name, ', ' ORDER BY first_appearance)
PostgreSQL 8.4 o posterior:
PostgreSQL 8.4 (en 2009) introdujo la función agregadaarray_agg(expression)
que concatena los valores en una matriz. Luego array_to_string()
se puede usar para dar el resultado deseado:
SELECT company_id, array_to_string(array_agg(employee), ', ')
FROM mytable
GROUP BY company_id;
string_agg
para versiones anteriores a la 8.4:
En caso de que alguien se encuentre con esto buscando una compatibilidad de compatibilidad para bases de datos anteriores a 9.0, es posible implementar todo string_agg
excepto la ORDER BY
cláusula.
Entonces, con la definición a continuación, esto debería funcionar igual que en una base de datos Postgres 9.x:
SELECT string_agg(name, '; ') AS semi_colon_separated_names FROM things;
Pero esto será un error de sintaxis:
SELECT string_agg(name, '; ' ORDER BY name) AS semi_colon_separated_names FROM things;
--> ERROR: syntax error at or near "ORDER"
Probado en 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
);
Variaciones personalizadas (todas las versiones de Postgres)
Antes de 9.0, no había una función agregada incorporada para concatenar cadenas. La implementación personalizada más simple ( sugerida por Vajda Gabo en esta publicación de la lista de correo , entre muchas otras) es usar la textcat
función incorporada (que se encuentra detrás del ||
operador):
CREATE AGGREGATE textcat_all(
basetype = text,
sfunc = textcat,
stype = text,
initcond = ''
);
Aquí está la CREATE AGGREGATE
documentación.
Esto simplemente pega todas las cadenas juntas, sin separador. Para obtener un "," insertado entre ellos sin tenerlo al final, es posible que desee hacer su propia función de concatenación y sustituirla por el "textcat" anterior. Aquí hay uno que armé y probé en 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 versión generará una coma incluso si el valor en la fila es nulo o vacío, por lo que obtendrá una salida como esta:
a, b, c, , e, , g
Si prefiere eliminar comas adicionales para generar esto:
a, b, c, e, g
Luego agregue un ELSIF
cheque a la función de esta manera:
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;