2010-04-01 27 views
169

Tengo una tabla y me gustaría extraer una fila por id con los valores de campo concatenados.Postgresql GROUP_CONCAT equivalente?

En mi mesa, por ejemplo, tengo esto:

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

Y me gustaría a salida:

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

En MySQL que fue capaz de utilizar la función de agregado GROUP_CONCAT, pero eso no parece funcionar aquí ... ¿Hay un equivalente para PostgreSQL u otra forma de lograr esto?

+0

No es una respuesta, pero echa un vistazo http://www.postgresonline.com/journal/index.php? /archives/14-CrossTab-Queries-in-PostgreSQL-using-tablefunc-contrib.html. – Kuberchaun

+1

http://stackoverflow.com/questions/1943433/postgresql-concat-ws-like-function –

+0

posible duplicado de [Simular grupo \ _concat función MySQL en SQL Server?] (Http://stackoverflow.com/questions/451415/simulating-group-concat-mysql-function-in-sql-server) – ntalbs

Respuesta

155

Esto es probablemente un buen punto de partida (versión 8.4+ solamente):

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

array_agg devuelve una matriz, pero se puede emitir ese texto y editar según sea necesario (ver aclaraciones, más adelante).

Antes de la versión 8.4, usted tiene que definir por sí mismo antes de su uso:

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

(parafraseado de la documentación de PostgreSQL)

Aclaraciones:

  • El resultado de lanzar una array to text es que la cadena resultante comienza y termina con llaves. Esos frenos deben eliminarse mediante algún método, si no se desean.
  • Casting ANYARRAY to TEXT simula mejor la salida de CSV, ya que los elementos que contienen comas incrustadas tienen una comilla doble en la salida en estilo CSV estándar. Ni array_to_string() ni string_agg() (la función "group_concat" agregada en 9.1) cita cadenas con comas incrustadas, lo que da como resultado un número incorrecto de elementos en la lista resultante.
  • La nueva función 9.1 string_agg() NO arroja los resultados internos a TEXTO primero. Entonces "string_agg (value_field)" generaría un error si value_field es un entero. "string_agg (value_field :: text)" sería obligatorio. El método array_agg() requiere solo un molde después de la agregación (en lugar de un molde por valor).
+0

Y en 9.0 tendrá listagg() –

+4

Para obtener CSV la consulta debe ser: id_field SELECT, array_to_string (ARRAY_AGG (value_field1), ' '), array_to_string (ARRAY_AGG (value_field2),',') DE data_table GROUP BY id_field – Nux

+2

No se puede usar array_to_string en todos los casos aquí. Si su value_field contiene una coma incrustada, el CSV resultante es incorrecto. Usar array_agg() y enviar a TEXT correctamente cita 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". Editaré para aclarar ese punto. –

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

va a hacer así.

+4

Éste también funciona antes de 9.0 - lo probó con 8.4. 5 – chrpes

+0

¡¡Excelente !!! Funciona para mi. Teste también Postgres 8.3.6. Tanques! – vandersondf

+0

¿Es posible hacer algo como en [este comentario] (http://stackoverflow.com/questions/2560946/postgresql-group-concat-equivalent#comment23843695_8803563), donde se agrega en un cierto orden? ¿Cómo manejaría la agrupación por una columna y el ordenamiento por otra (por ejemplo, para concatenar variables dentro de un conjunto de datos longitudinales)? –

178

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

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

Tenga en cuenta que la sintaxis también le permite especificar el orden de los valores en la cadena (o matriz, usando 'array_agg'), p. Ej. 'string_agg (some_column, ',' ORDER BY some_column)' o incluso 'string_agg (surname || ',' || forename, ';' ORDER BY apellido, nombre de pila)' – IMSoP

+0

@a_horse_with_no_name Veo muchas de sus excelentes publicaciones en SO mientras estoy trabajando en varios problemas de Postgres. No veo una forma de contactarte en tu perfil. ¿Está abierto a la comunicación/a trabajar en proyectos fuera de SO? Disculpas por hacerte un ping a través de un comentario si no es así. Si está abierto a una posible colaboración/trabajo fuera de SO, puede contactarme desde mi perfil si es así: http://stackoverflow.com/users/2565593/steve-midgley - Usted está haciendo un trabajo increíble aquí - gracias ! (Y a los editores me baso en meta comentarios como este para dejar este comentario: http://meta.stackexchange.com/a/58715/278168) –

8

Trate de esta manera:

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