Cómo usar GROUP_CONCAT en un CONCAT en MySQL

117

Si tengo una tabla con los siguientes datos en MySQL:

id       Name       Value
1          A          4
1          A          5
1          B          8
2          C          9

¿Cómo lo consigo en el siguiente formato?

id         Column
1          A:4,5,B:8
2          C:9


Creo que tengo que usar GROUP_CONCAT. Pero no estoy seguro de cómo funciona.

Biswa
fuente

Respuestas:

160
select id, group_concat(`Name` separator ',') as `ColumnName`
from
(
  select 
    id, 
    concat(`Name`, ':', group_concat(`Value` separator ',')) as `Name`
  from mytbl
  group by 
    id, 
    `Name`
) tbl
group by id;

Puedes verlo implementado aquí: Sql Fiddle Demo . Exactamente lo que necesitas.

Actualice Splitting en dos pasos. Primero obtenemos una tabla que tiene todos los valores (separados por comas) contra un [Nombre, id] único. Luego, de la tabla obtenida, obtenemos todos los nombres y valores como un valor único contra cada identificación única. Vea esto explicado aquí. Demostración de SQL Fiddle (desplácese hacia abajo ya que tiene dos conjuntos de resultados)

Editar Hubo un error al leer la pregunta, lo había agrupado solo por id. Pero se necesitan dos group_contacts si (los valores deben concatenarse agrupados por nombre e id y luego sobre todos por id). La respuesta anterior fue

select 
id,group_concat(concat(`name`,':',`value`) separator ',')
as Result from mytbl group by id

Puedes verlo implementado aquí: SQL Fiddle Demo

Sami
fuente
Esto no da lo que pidió Biswa.
eisberg
3
Creo que es importante advertir a la gente que usar solo un tipo de separador podría ser una desventaja. Sugiero hacer el separador de "nombre" como punto y coma (;), y el separador de valores puede permanecer como coma (,)
Fandi Susanto
4
Tenga en cuenta también que GROUP_CONCATpuede truncar silenciosamente su salida a group_concat_max_len. SET group_concat_max_len=...ayudará, pero de todos modos es una buena idea comprobar que la longitud devuelta (¿bytes?) es menor que group_concat_max_len.
tuomassalo
2
Tenga en cuenta también que group_concat encuentra un solo valor NULL omitirá toda la fila que lo contenía. Resuelvo esto en la segunda advertencia aquí .
MatrixManAtYrService
1
Si alguien tiene problemas con el enlace SQL Fiddle dado en respuesta. Working Fiddle está aquí: sqlfiddle.com/#!9/42f994/601/0
Hitesh
21

Tratar:

CREATE TABLE test (
  ID INTEGER,
  NAME VARCHAR (50),
  VALUE INTEGER
);

INSERT INTO test VALUES (1, 'A', 4);
INSERT INTO test VALUES (1, 'A', 5);
INSERT INTO test VALUES (1, 'B', 8);
INSERT INTO test VALUES (2, 'C', 9);

SELECT ID, GROUP_CONCAT(NAME ORDER BY NAME ASC SEPARATOR ',')
FROM (
  SELECT ID, CONCAT(NAME, ':', GROUP_CONCAT(VALUE ORDER BY VALUE ASC SEPARATOR ',')) AS NAME
  FROM test
  GROUP BY ID, NAME
) AS A
GROUP BY ID;

Violín SQL: http://sqlfiddle.com/#!2/b5abe/9/0

Eisberg
fuente
2
Sí eisberg +1. Tu respuesta es bastante precisa y anterior. Cometí un error en mi primera respuesta
Sami
9
SELECT ID, GROUP_CONCAT(CONCAT_WS(':', NAME, VALUE) SEPARATOR ',') AS Result 
FROM test GROUP BY ID
Juan
fuente
7
Sería bueno si pudiera agregar alguna descripción a su respuesta. Esta es una sugerencia para mejorar esta y futuras respuestas. ¡Gracias!
Luís Cruz
5

En primer lugar, no veo la razón para tener una identificación que no sea única, pero supongo que es una identificación que se conecta a otra tabla. En segundo lugar, no hay necesidad de subconsultas, lo que supera al servidor. Haces esto en una consulta, como esta

SELECT id,GROUP_CONCAT(name, ':', value SEPARATOR "|") FROM sample GROUP BY id

Obtiene resultados rápidos y correctos, y puede dividir el resultado por ese SEPARADOR "|". Siempre uso este separador, porque es imposible encontrarlo dentro de una cadena, por eso es único. No hay problema en tener dos A, solo identificas el valor. O puede tener una columna más, con la letra, que es aún mejor. Me gusta esto :

SELECT id,GROUP_CONCAT(DISTINCT(name)), GROUP_CONCAT(value SEPARATOR "|") FROM sample GROUP BY name
Lucian Minea
fuente
2
 SELECT id, GROUP_CONCAT(CONCAT_WS(':', Name, CAST(Value AS CHAR(7))) SEPARATOR ',') AS result 
    FROM test GROUP BY id

debe usar cast o convertir, de lo contrario se devolverá BLOB

el resultado es

id         Column
1          A:4,A:5,B:8
2          C:9

tienes que manejar el resultado una vez más por un programa como Python o Java

lglcomcn
fuente
0

IF OBJECT_ID('master..test') is not null Drop table test

CREATE TABLE test (ID INTEGER, NAME VARCHAR (50), VALUE INTEGER );
INSERT INTO test VALUES (1, 'A', 4);
INSERT INTO test VALUES (1, 'A', 5);
INSERT INTO test VALUES (1, 'B', 8);
INSERT INTO test VALUES (2, 'C', 9);

select distinct NAME , LIST = Replace(Replace(Stuff((select ',', +Value from test where name = _a.name for xml path('')), 1,1,''),'<Value>', ''),'</Value>','') from test _a order by 1 desc

El nombre de mi tabla es prueba, y para la concatenación utilizo la sintaxis For XML Path (''). La función de cosas inserta una cadena en otra cadena. Elimina una longitud especificada de caracteres en la primera cadena en la posición inicial y luego inserta la segunda cadena en la primera cadena en la posición inicial.

Las funciones STUFF se ven así: STUFF (character_expression, start, length, character_expression)

character_expression Es una expresión de datos de caracteres. character_expression puede ser una constante, variable o columna de caracteres o datos binarios.

inicio Es un valor entero que especifica la ubicación para iniciar la eliminación y la inserción. Si el inicio o la longitud son negativos, se devuelve una cadena nula. Si start es más largo que el primer character_expression, se devuelve una cadena nula. start puede ser de tipo bigint.

longitud Es un número entero que especifica el número de caracteres que se eliminarán. Si la longitud es mayor que la primera expresión_caracteres, la eliminación se produce hasta el último carácter de la última expresión_caracteres. la longitud puede ser de tipo bigint.

Novy
fuente
0

SELECT id, Group_concat ( column) FROM (SELECT id, Concat ( name, ':', Group_concat ( value)) AS column FROM mytbl GROUP BY id, nombre) tbl GROUP BY id;

Mrigank Shekhar
fuente