¿Cómo concatenar cadenas de un campo de cadena en una consulta 'agrupar por' de PostgreSQL?

Resuelto Guy C asked hace 16 años • 14 respuestas

Estoy buscando una manera de concatenar las cadenas de un campo dentro de un grupo mediante consulta. Entonces, por ejemplo, tengo una tabla:

IDENTIFICACIÓN ID DE LA COMPAÑÍA EMPLEADO
1 1 ana
2 1 Factura
3 2 Villancico
4 2 dave

y quería agrupar por company_id para obtener algo como:

ID DE LA COMPAÑÍA EMPLEADO
1 Ana, Bill
2 carol, dave

Hay una función incorporada en MySQL para hacer esto group_concat

Guy C avatar Sep 04 '08 21:09 Guy C
Aceptado

PostgreSQL 9.0 o posterior:

Modern Postgres (desde 2010) tiene la string_agg(expression, delimiter)función que hará exactamente lo que el autor de la pregunta estaba buscando:

SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;

Postgres 9 también agregó la capacidad de especificar una ORDER BYcláusula en cualquier expresión agregada ; de lo contrario, tendrá que ordenar todos sus resultados o lidiar con un orden indefinido. Entonces ahora puedes escribir:

SELECT company_id, string_agg(employee, ', ' ORDER BY employee)
FROM mytable
GROUP BY company_id;

PostgreSQL 8.4.x:

Tenga en cuenta que el soporte para Postgres 8.4 finalizó en 2014 , por lo que probablemente debería actualizar por razones más importantes que la agregación de cadenas.

PostgreSQL 8.4 (en 2009) introdujo la función agregadaarray_agg(expression) que recopila los valores en una matriz. Luego array_to_string()se puede utilizar para dar el resultado deseado:

SELECT company_id, array_to_string(array_agg(employee), ', ')
FROM mytable
GROUP BY company_id;

PostgreSQL 8.3.x y anteriores:

Cuando se planteó originalmente esta pregunta, 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 correotextcat , entre muchas otras) es usar la función incorporada :

CREATE AGGREGATE textcat_all(
  basetype    = text,
  sfunc       = textcat,
  stype       = text,
  initcond    = ''
);

Aquí está la CREATE AGGREGATEdocumentación.

Esto simplemente pega todas las cuerdas juntas, sin separador. Para poder insertar un "," entre ellos sin tenerlo al final, es posible que desee crear 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 de la fila es nulo o está vacío, por lo que obtendrá un resultado como este:

a, b, c, , e, , g

Si prefiere eliminar comas adicionales para generar esto:

a, b, c, e, g

Luego agregue una ELSIFmarca a la función 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;
Neall avatar Sep 04 '2008 15:09 Neall

¿Qué tal si utilizamos las funciones de matriz integradas de Postgres? Al menos en 8.4, esto funciona de inmediato:

SELECT company_id, array_to_string(array_agg(employee), ',')
FROM mytable
GROUP BY company_id;
Markus Döring avatar Feb 18 '2010 22:02 Markus Döring