Posso concatenar várias linhas do MySQL em um campo?


1214

Usando MySQL, eu posso fazer algo como:

SELECT hobbies FROM peoples_hobbies WHERE person_id = 5;

Minha saída:

shopping
fishing
coding

mas eu só quero 1 linha, 1 col:

Saída esperada:

shopping, fishing, coding

O motivo é que estou selecionando vários valores de várias tabelas e, depois de todas as associações, tenho muito mais linhas do que gostaria.

Procurei uma função no MySQL Doc e ela não parece com as funções CONCATou CONCAT_WSaceita conjuntos de resultados.

Então, alguém aqui sabe como fazer isso?


9
Eu escrevi uma pequena demonstração sobre como utilizar group_concat que pode ser útil para você: giombetti.com/2013/06/06/mysql-group_concat
Marc Giombetti

Respostas:


1739

Você pode usar GROUP_CONCAT:

SELECT person_id, GROUP_CONCAT(hobbies SEPARATOR ', ')
FROM peoples_hobbies
GROUP BY person_id;

Como Ludwig afirmou em seu comentário, você pode adicionar o DISTINCToperador para evitar duplicatas:

SELECT person_id, GROUP_CONCAT(DISTINCT hobbies SEPARATOR ', ')
FROM peoples_hobbies 
GROUP BY person_id;

Como Jan afirmou em seu comentário, você também pode classificar os valores antes de implodi-lo usando ORDER BY:

SELECT person_id, GROUP_CONCAT(hobbies ORDER BY hobbies ASC SEPARATOR ', ')
FROM peoples_hobbies
GROUP BY person_id;

Como Dag afirmou em seu comentário, há um limite de 1024 bytes no resultado. Para resolver isso, execute esta consulta antes de sua consulta:

SET group_concat_max_len = 2048;

Claro, você pode mudar de 2048acordo com suas necessidades. Para calcular e atribuir o valor:

SET group_concat_max_len = CAST(
    (SELECT SUM(LENGTH(hobbies)) + COUNT(*) * LENGTH(', ')
    FROM peoples_hobbies 
    GROUP BY person_id)
    AS UNSIGNED
);

155
Apenas estar ciente da limitação de 1024 bytes na coluna resultante (ver parâmetro group_concat_max_len )
Dag

81
E adicionando o DISTINCTparâmetro, você não receberá duplos. ... GROUP_CONCAT(DISTINCT hobbies)
Ludwig

3
Minha necessidade era obter todos os dados de uma coluna. Não use a cláusula GROUP BY para fazer isso. Exemplo: SELECT GROUP_CONCAT (envia um e-mail para SEPARATOR ',') FROM usuários;
Jonathan Bergeron

1
Obrigado, eu não sabia que havia um limite de duração do concat do grupo. Eu precisava disso para contornar uma lista de monstros que eu gerava.
Patrick

9
Se você quiser passatempos ordenação no uso corda implodiu resultante:SELECT person_id, GROUP_CONCAT(hobbies ORDER BY hobbies ASC SEPARATOR ', ') FROM peoples_hobbies GROUP BY person_id
Jan

106

Veja GROUP_CONCATse a sua versão do MySQL (4.1) é compatível. Veja a documentação para mais detalhes.

Seria algo como:

  SELECT GROUP_CONCAT(hobbies SEPARATOR ', ') 
  FROM peoples_hobbies 
  WHERE person_id = 5 
  GROUP BY 'all';

11
Eu acho que isso group by 'all'não é necessário (além disso indesejável), porque isso atribui a todas as linhas de seqüência de caracteres alle, em seguida, compara as seqüências de caracteres entre essas linhas. Estou certo?
precisa

74

Sintaxe alternativa para concatenar várias linhas individuais

AVISO: Este post deixará você com fome.

Dado:

Eu me vi querendo selecionar várias linhas individuais - em vez de um grupo - e concatenar em um determinado campo.

Digamos que você tenha uma tabela de IDs de produtos, seus nomes e preços:

+------------+--------------------+-------+
| product_id | name               | price |
+------------+--------------------+-------+
|         13 | Double Double      |     5 |
|         14 | Neapolitan Shake   |     2 |
|         15 | Animal Style Fries |     3 |
|         16 | Root Beer          |     2 |
|         17 | Lame T-Shirt       |    15 |
+------------+--------------------+-------+

Então você tem um ajax sofisticado que lista esses filhotes como caixas de seleção.

Seu usuário de hipopótamo com fome seleciona 13, 15, 16. Hoje não há sobremesa para ela ...

Encontrar:

Uma maneira de resumir a ordem do usuário em uma linha, com o mysql puro.

Solução:

Use GROUP_CONCATcom a INcláusula the :

mysql> SELECT GROUP_CONCAT(name SEPARATOR ' + ') AS order_summary FROM product WHERE product_id IN (13, 15, 16);

Quais saídas:

+------------------------------------------------+
| order_summary                                  |
+------------------------------------------------+
| Double Double + Animal Style Fries + Root Beer |
+------------------------------------------------+

Solução bônus:

Se você também quiser o preço total, jogue SUM():

mysql> SELECT GROUP_CONCAT(name SEPARATOR ' + ') AS order_summary, SUM(price) AS total FROM product WHERE product_id IN (13, 15, 16);
+------------------------------------------------+-------+
| order_summary                                  | total |
+------------------------------------------------+-------+
| Double Double + Animal Style Fries + Root Beer |    10 |
+------------------------------------------------+-------+

PS: Desculpas se você não tiver um In-N-Out por perto ...


11
Embora essa seja uma boa resposta, isso soa mais como publicidade do que puramente como resposta. Ainda é uma boa resposta bem formatada.
FliiFe

1
Posso obter ajuda stackoverflow.com/q/60278898/11697039 @elbowlobstercowstand
zus 18/02

39

Você pode alterar o comprimento máximo do GROUP_CONCATvalor configurando o group_concat_max_lenparâmetro

Veja detalhes na documentação do MySQL .



25

No meu caso, eu tinha uma linha de IDs e era necessário convertê-la em char, caso contrário, o resultado foi codificado em formato binário:

SELECT CAST(GROUP_CONCAT(field SEPARATOR ',') AS CHAR) FROM table

1
Obrigado! Sem CASTeu tinha valores como [BLOB - 14 Bytes]no resultado!
Mel_T 07/02

1
Posso obter ajuda stackoverflow.com/q/60278898/11697039 @Fedir RYKHTIK
zus 18/02

16

Use a variável de sessão MySQL (5.6.13) e o operador de atribuição como os seguintes

SELECT @logmsg := CONCAT_ws(',',@logmsg,items) FROM temp_SplitFields a;

então você pode obter

test1,test11

2
é mais rápido que GROUP_CONCAT?
jave.web

1
Eu testei isso no PHPMyAdmin com o servidor MySQL v5.6.17 em uma coluna de descrição (varchar (50)) em uma tabela de teste, mas ele retorna um campo BLOB para cada registro:SELECT @logmsg := CONCAT_ws(',',@logmsg,description) from test
Jan

14

Eu tive uma consulta mais complicada e descobri que precisava usar GROUP_CONCATem uma consulta externa para fazê-la funcionar:

Consulta original:

SELECT DISTINCT userID 
FROM event GROUP BY userID 
HAVING count(distinct(cohort))=2);

Imploded:

SELECT GROUP_CONCAT(sub.userID SEPARATOR ', ') 
FROM (SELECT DISTINCT userID FROM event 
GROUP BY userID HAVING count(distinct(cohort))=2) as sub;

Espero que isso possa ajudar alguém.


9

Para alguém olhando aqui como usar GROUP_CONCATcom subconsulta - postando este exemplo

SELECT i.*,
(SELECT GROUP_CONCAT(userid) FROM favourites f WHERE f.itemid = i.id) AS idlist
FROM items i
WHERE i.id = $someid

Portanto, GROUP_CONCATdeve ser usado dentro da subconsulta, não envolvendo-a.


1
Este foi exatamente o que eu estava procurando
bumerang

7

Tente o seguinte:

DECLARE @Hobbies NVARCHAR(200) = ' '

SELECT @Hobbies = @Hobbies + hobbies + ',' FROM peoples_hobbies WHERE person_id = 5;

2
Isto é o que recebi: 'Tipo de declaração não reconhecido. (perto de "DECLARE" na posição 0) '
Istiaque Ahmed 07/11

1

nós temos duas maneiras de concatenar colunas no MySql

select concat(hobbies) as `Hobbies` from people_hobbies where 1

Ou

select group_concat(hobbies) as `Hobbies` from people_hobbies where 1
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.