Como usar GROUP_CONCAT em um CONCAT no MySQL

117

Se eu tiver uma tabela com os seguintes dados em MySQL:

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

como faço para colocá-lo no seguinte formato?

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


Acho que tenho que usar GROUP_CONCAT. Mas não tenho certeza de como funciona.

Biswa
fonte

Respostas:

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;

Você pode vê-lo implementado aqui: Sql Fiddle Demo . Exatamente o que você precisa.

Atualize a divisão em duas etapas. Primeiro, obtemos uma tabela com todos os valores (separados por vírgula) em relação a um único [Nome, id]. Então, da tabela obtida, obtemos todos os nomes e valores como um único valor em relação a cada id único. Veja isso explicado aqui. SQL Fiddle Demo (role para baixo, pois tem dois conjuntos de resultados)

Editar Ocorreu um erro ao ler a pergunta, agrupei apenas por id. Mas dois group_contacts são necessários se (os valores devem ser concatenados agrupados por Nome e id e, em seguida, todos por id). A resposta anterior era

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

Você pode ver isso implementado aqui: SQL Fiddle Demo

Sami
fonte
Isso não dá o que Biswa pediu.
eisberg
3
Acho importante alertar as pessoas que usar apenas um tipo de separador pode ser desvantajoso. Eu sugiro fazer o separador "nome" como ponto e vírgula (;), e o separador de valores pode permanecer como vírgula (,)
Fandi Susanto
4
Observe também que GROUP_CONCATpode truncar silenciosamente sua saída para group_concat_max_len. SET group_concat_max_len=...vai ajudar, mas é uma boa idéia, de qualquer maneira, verificar se o comprimento retornado (byte?) é menor que group_concat_max_len.
tuomassalo
2
Observe também que group_concat encontra um único valor NULL e omite a linha inteira que o continha. Eu trabalho em torno disso na segunda advertência aqui .
MatrixManAtYrService
1
Se alguém está enfrentando problemas com o link SQL Fiddle fornecido na resposta. Working Fiddle está aqui: sqlfiddle.com/#!9/42f994/601/0
Hitesh
21

Experimentar:

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;

SQL Fiddle: http://sqlfiddle.com/#!2/b5abe/9/0

Eisberg
fonte
2
Sim eisberg +1. Sua resposta é bastante precisa e anterior. Eu cometi um erro na minha primeira resposta
Sami
9
SELECT ID, GROUP_CONCAT(CONCAT_WS(':', NAME, VALUE) SEPARATOR ',') AS Result 
FROM test GROUP BY ID
John
fonte
7
Seria bom se você pudesse adicionar alguma descrição à sua resposta. Esta é uma sugestão para melhorar esta e futuras respostas. Obrigado!
Luís Cruz
5

Em primeiro lugar, não vejo razão para ter um ID que não seja único, mas acho que é um ID que se conecta a outra tabela. Em segundo lugar, não há necessidade de subconsultas, o que sobrecarrega o servidor. Você faz isso em uma consulta, assim

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

Você obtém resultados rápidos e corretos e pode dividir o resultado pelo SEPARADOR "|". Sempre utilizo esse separador, pois é impossível encontrá-lo dentro de uma string, por isso é único. Não há problema em ter dois A's, você identifica apenas o valor. Ou pode ficar com mais uma coluna, com a letra, que é ainda melhor. Como isso :

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

você deve usar cast ou converter, caso contrário será return BLOB

resultado é

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

você tem que lidar com o resultado mais uma vez por programa como python ou java

lglcomcn
fonte
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

Meu nome de tabela é teste e, para concatinação, uso a sintaxe For XML Path (''). A função stuff insere uma string em outra string. Ele exclui um comprimento especificado de caracteres na primeira string na posição inicial e, em seguida, insere a segunda string na primeira string na posição inicial.

As funções STUFF têm a seguinte aparência: STUFF (expressão_caractere, início, comprimento, expressão_caractere)

character_expression É uma expressão de dados de caractere. character_expression pode ser uma constante, variável ou coluna de dados de caracteres ou binários.

start É um valor inteiro que especifica o local para iniciar a exclusão e inserção. Se o início ou comprimento for negativo, uma string nula será retornada. Se o início for mais longo do que o primeiro character_expression, uma string nula será retornada. start pode ser do tipo bigint.

comprimento É um número inteiro que especifica o número de caracteres a serem excluídos. Se o comprimento for maior que o primeiro character_expression, a exclusão ocorrerá até o último caractere na última character_expression. comprimento pode ser do tipo bigint.

Novy
fonte
0

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

Mrigank Shekhar
fonte