Puis-je concaténer plusieurs lignes MySQL en un seul champ?

1214

En utilisant MySQL, je peux faire quelque chose comme:

SELECT hobbies FROM peoples_hobbies WHERE person_id = 5;

Ma sortie:

shopping
fishing
coding

mais je veux juste 1 ligne, 1 col:

Production attendue:

shopping, fishing, coding

La raison en est que je sélectionne plusieurs valeurs dans plusieurs tables et, après toutes les jointures, j'ai beaucoup plus de lignes que je ne le souhaiterais.

J'ai cherché une fonction sur MySQL Doc et elle ne ressemble pas aux fonctions CONCATou CONCAT_WSacceptent les jeux de résultats.

Alors, quelqu'un ici sait-il comment faire cela?

Dean plutôt
la source
9
Je viens d'écrire une petite démo sur la façon d'utiliser group_concat qui pourrait vous être utile: giombetti.com/2013/06/06/mysql-group_concat
Marc Giombetti

Réponses:

1739

Vous pouvez utiliser GROUP_CONCAT:

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

Comme Ludwig l'a déclaré dans son commentaire, vous pouvez ajouter l' DISTINCTopérateur pour éviter les doublons:

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

Comme Jan l'a déclaré dans leur commentaire, vous pouvez également trier les valeurs avant de l'imploser en utilisant ORDER BY:

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

Comme Dag l'a déclaré dans son commentaire, le résultat est limité à 1024 octets. Pour résoudre ce problème, exécutez cette requête avant votre requête:

SET group_concat_max_len = 2048;

Bien sûr, vous pouvez changer 2048selon vos besoins. Pour calculer et affecter la valeur:

SET group_concat_max_len = CAST(
    (SELECT SUM(LENGTH(hobbies)) + COUNT(*) * LENGTH(', ')
    FROM peoples_hobbies 
    GROUP BY person_id)
    AS UNSIGNED
);
che
la source
155
Soyez juste conscient de la limitation de 1024 octets dans la colonne résultante (voir paramètre group_concat_max_len )
Dag
81
Et en ajoutant le DISTINCTparamètre, vous n'obtiendrez aucun double. ... GROUP_CONCAT(DISTINCT hobbies)
Ludwig
3
Mon besoin était d'obtenir TOUTES les données d'une colonne. N'utilisez pas la clause GROUP BY pour ce faire. Exemple: SELECT GROUP_CONCAT (email SEPARATOR ',') FROM users;
Jonathan Bergeron
1
Merci, je ne savais pas qu'il y avait une limite de longueur pour la concaténation de groupe. J'en avais besoin pour contourner une liste de monstres que j'avais générée.
Patrick
9
Si vous voulez passe - temps de tri dans l'utilisation de la chaîne implosé résultant:SELECT person_id, GROUP_CONCAT(hobbies ORDER BY hobbies ASC SEPARATOR ', ') FROM peoples_hobbies GROUP BY person_id
Jan
106

Regardez GROUP_CONCATsi votre version MySQL (4.1) le supporte. Voir la documentation pour plus de détails.

Cela ressemblerait à quelque chose comme:

  SELECT GROUP_CONCAT(hobbies SEPARATOR ', ') 
  FROM peoples_hobbies 
  WHERE person_id = 5 
  GROUP BY 'all';
lpfavreau
la source
11
Je pense que ce group by 'all'n'est pas nécessaire (d'ailleurs indésirable), car cela affecte à toutes les lignes de chaîne allet compare ensuite les chaînes entre ces lignes. Ai-je raison?
Krzysiek
74

Syntaxe alternative pour concaténer plusieurs lignes individuelles

AVERTISSEMENT: ce message vous donnera faim.

Donné:

Je me suis retrouvé à vouloir sélectionner plusieurs lignes individuelles - au lieu d'un groupe - et à concaténer sur un certain champ.

Supposons que vous ayez un tableau des identifiants des produits et leurs noms et prix:

+------------+--------------------+-------+
| 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 |
+------------+--------------------+-------+

Ensuite, vous avez un ajax fantaisie-schmancy qui répertorie ces chiots comme des cases à cocher.

Votre utilisateur hippopotame affamé sélectionne 13, 15, 16. Pas de dessert pour elle aujourd'hui ...

Trouver:

Un moyen de résumer la commande de votre utilisateur sur une seule ligne, avec pur mysql.

Solution:

À utiliser GROUP_CONCATavec la INclause :

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

Quelles sorties:

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

Solution bonus:

Si vous voulez aussi le prix total, ajoutez 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: Toutes mes excuses si vous n'avez pas d' In-N-Out à proximité ...

coude
la source
11
Même si c'est une bonne réponse, cela ressemble plus à de la publicité qu'à une simple réponse. Encore une bonne réponse bien formulée.
FliiFe
1
Puis-je obtenir de l'aide stackoverflow.com/q/60278898/11697039 @elbowlobstercowstand
zus
39

Vous pouvez modifier la longueur maximale de la GROUP_CONCATvaleur en définissant le group_concat_max_lenparamètre.

Voir les détails dans la documentation MySQL .

pau.moreno
la source
25

Dans mon cas, j'avais une rangée d'identifiants, et il était nécessaire de la convertir en char, sinon le résultat était encodé au format binaire:

SELECT CAST(GROUP_CONCAT(field SEPARATOR ',') AS CHAR) FROM table
Fedir RYKHTIK
la source
1
Merci! Sans, CASTj'avais des valeurs COMME [BLOB - 14 Bytes]dans le résultat!
Mel_T
1
Puis-je obtenir de l'aide stackoverflow.com/q/60278898/11697039 @Fedir RYKHTIK
zus
16

Utilisez la variable de session MySQL (5.6.13) et l'opérateur d'affectation comme suit

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

alors vous pouvez obtenir

test1,test11
Shen liang
la source
2
est-ce plus rapide que GROUP_CONCAT?
jave.web
1
Je l' ai testé ce sous PHPMyAdmin avec le serveur MySQL v5.6.17 sur une Description colonne (varchar (50)) dans un test de table , mais il retourne un champ blob pour chaque enregistrement:SELECT @logmsg := CONCAT_ws(',',@logmsg,description) from test
Jan
14

J'avais une requête plus compliquée et j'ai constaté que je devais l'utiliser GROUP_CONCATdans une requête externe pour la faire fonctionner:

Requête d'origine:

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

Implosé:

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

J'espère que cela pourrait aider quelqu'un.

Alex Bowyer
la source
9

Pour quelqu'un qui regarde ici comment utiliser la GROUP_CONCATsous-requête - publier cet exemple

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

Il GROUP_CONCATdoit donc être utilisé à l'intérieur de la sous-requête, pas en l'enveloppant.

Oleg Abrazhaev
la source
1
C'est exactement ce que je cherchais
bumerang
7

Essaye ça:

DECLARE @Hobbies NVARCHAR(200) = ' '

SELECT @Hobbies = @Hobbies + hobbies + ',' FROM peoples_hobbies WHERE person_id = 5;
thejustv
la source
2
Voici ce que j'ai obtenu: 'Type d'instruction non reconnu. (près de "DECLARE" en position 0) '
Istiaque Ahmed
1

nous avons deux façons de concaténer des colonnes dans MySql

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

Ou

select group_concat(hobbies) as `Hobbies` from people_hobbies where 1
raghavendra
la source