Postgresql GROUP_CONCAT equivalente?


248

Tengo una tabla y me gustaría extraer una fila por id con valores de campo concatenados.

En mi tabla, por ejemplo, tengo esto:

TM67 | 4  | 32556
TM67 | 9  | 98200
TM67 | 72 | 22300
TM99 | 2  | 23009
TM99 | 3  | 11200

Y me gustaría dar salida:

TM67 | 4,9,72 | 32556,98200,22300
TM99 | 2,3    | 23009,11200

En MySQL pude usar la función agregada GROUP_CONCAT, pero eso no parece funcionar aquí ... ¿Hay un equivalente para PostgreSQL u otra forma de lograr esto?


No es una respuesta, pero echa un vistazo a postgresonline.com/journal/index.php?/archives/… .
Kuberchaun



1
Creo que la mejor respuesta todavía está en otra pregunta: stackoverflow.com/a/47638417/243233
Jus12

Respuestas:


237

Este es probablemente un buen punto de partida (solo la versión 8.4+):

SELECT id_field, array_agg(value_field1), array_agg(value_field2)
FROM data_table
GROUP BY id_field

array_agg devuelve una matriz, pero puede ENVIARLA al texto y editarla según sea necesario (consulte las aclaraciones a continuación).

Antes de la versión 8.4, debe definirlo usted mismo antes de usar:

CREATE AGGREGATE array_agg (anyelement)
(
    sfunc = array_append,
    stype = anyarray,
    initcond = '{}'
);

(parafraseado de la documentación de PostgreSQL)

Aclaraciones:

  • El resultado de convertir una matriz en texto es que la cadena resultante comienza y termina con llaves. Esos brackets deben eliminarse por algún método, si no se desean.
  • Transmitir ANYARRAY a TEXT simula mejor la salida CSV ya que los elementos que contienen comas incrustadas se citan dos veces en la salida en el estilo CSV estándar. Ni array_to_string () ni string_agg () (la función "group_concat" agregada en 9.1) citan cadenas con comas incrustadas, lo que resulta en un número incorrecto de elementos en la lista resultante.
  • La nueva función 9.1 string_agg () NO convierte primero los resultados internos a TEXTO. Entonces "string_agg (value_field)" generaría un error si value_field es un entero. Se requeriría "string_agg (value_field :: text)". El método array_agg () requiere solo una conversión después de la agregación (en lugar de una conversión por valor).

1
Y en 9.0 tendrás listagg ()
Scott Bailey

66
Para obtener CSV, la consulta debe ser: SELECT id_field, array_to_string (array_agg (value_field1), ','), array_to_string (array_agg (value_field2), ',') FROM data_table GROUP BY id_field
Nux

2
No puede usar array_to_string en todos los casos aquí. Si su value_field contiene una coma incrustada, el CSV resultante es incorrecto. El uso de array_agg () y la conversión a TEXTO cita correctamente las cadenas con comas incrustadas. La única advertencia es que también incluye los corchetes iniciales y finales, de ahí mi declaración "y editar según sea necesario". Lo editaré para aclarar ese punto.
Matthew Wood

FYI: aquí hay un enlace a documentos en array_agg en 8.4
Michael Rusch

256

Desde 9.0 esto es aún más fácil:

SELECT id, 
       string_agg(some_column, ',')
FROM the_table
GROUP BY id

32
Tenga en cuenta que la sintaxis también le permite especificar el orden de los valores en la cadena (o matriz, usando array_agg), por ejemplo, string_agg(some_column, ',' ORDER BY some_column)o inclusostring_agg(surname || ', ' || forename, '; ' ORDER BY surname, forename)
IMSoP

8
Es increíble que distinctfuncione con string_agg, por lo que se puede usarstring_agg(distinct some_solumn, ',')
arun el

3
Tenga en cuenta que es posible que deba convertir el valor de la columna TEXTsi es un valor no encadenable (es decir uuid). Esto se vería asístring_agg(some_column::text, ',')
Kendall, el

48
SELECT array_to_string(array(SELECT a FROM b),', ');

Lo haré igual.


¿Es posible hacer algo como en este comentario , donde se agregan en un cierto orden? ¿Cómo manejaría la agrupación por una columna y la ordenación por otra (por ejemplo, para concatenar variables dentro de un conjunto de datos longitudinales)?
Michael A

15

Intenta así:

select field1, array_to_string(array_agg(field2), ',')
from table1
group by field1;

2

y la versión para trabajar en el tipo de matriz :

select
  array_to_string(
    array(select distinct unnest(zip_codes) from table),
    ', '
);

Respuesta duplicada, @max_spy dijo lo mismo hace cinco años
Emil Vikström,

@ EmilVikström: tienes derecho a equivocarte, pero lee con cuidado. No solo es diferente, sino que di un ejemplo, que funciona con el tipo de matriz, como ser zip_codes character varying(5)[]. Además, he verificado que, para mi propósito, se necesita unnest; de lo contrario, verá ERROR: cannot accumulate arrays of different dimensionality.
Sławomir Lenart

1

Mi sugestion en postgresql

SELECT cpf || ';' || nome || ';' || telefone  
FROM (
      SELECT cpf
            ,nome
            ,STRING_AGG(CONCAT_WS( ';' , DDD_1, TELEFONE_1),';') AS telefone 
      FROM (
            SELECT DISTINCT * 
            FROM temp_bd 
            ORDER BY cpf DESC ) AS y
      GROUP BY 1,2 ) AS x   

1
¿Por qué estás haciendo ORDER BYuna consulta interna? ¿No se perderá el pedido de todos modos?
mypetlion

-1

Espero que debajo de Oracle la consulta funcione.

Select First_column,LISTAGG(second_column,',') 
    WITHIN GROUP (ORDER BY second_column) as Sec_column, 
    LISTAGG(third_column,',') 
    WITHIN GROUP (ORDER BY second_column) as thrd_column 
FROM tablename 
GROUP BY first_column

Lo probé en rextester.com/l/postgresql_online_compiler y no funcionó: 42883: la función listagg (texto, desconocido, texto) no existe
Manuel Romeiro

Oracle tiene diferentes sintaxis y funciones que postgres.
Herman J. Radtke III
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.