Posso concatenare più righe MySQL in un campo?


1214

Utilizzando MySQL, posso fare qualcosa del tipo:

SELECT hobbies FROM peoples_hobbies WHERE person_id = 5;

La mia uscita:

shopping
fishing
coding

ma invece voglio solo 1 riga, 1 colonna:

Uscita prevista:

shopping, fishing, coding

Il motivo è che sto selezionando più valori da più tabelle e dopo tutto i join ho molte più righe di quelle che vorrei.

Ho cercato una funzione su MySQL Doc e non sembra che le funzioni CONCATo CONCAT_WSaccettino i set di risultati.

Qualcuno qui sa come fare?


9
Ho appena scritto una piccola demo su come usare group_concat che potrebbe esserti utile: giombetti.com/2013/06/06/mysql-group_concat
Marc Giombetti

Risposte:


1739

Puoi usare GROUP_CONCAT:

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

Come ha affermato Ludwig nel suo commento, è possibile aggiungere l' DISTINCToperatore per evitare duplicati:

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

Come ha affermato Jan nel loro commento, puoi anche ordinare i valori prima di imploderlo usando ORDER BY:

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

Come ha affermato Dag nel suo commento, c'è un limite di 1024 byte sul risultato. Per risolvere questo, eseguire questa query prima della query:

SET group_concat_max_len = 2048;

Certo, puoi cambiare in 2048base alle tue esigenze. Per calcolare e assegnare il valore:

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

155
Basta essere consapevoli della limitazione di 1024 byte nella colonna risultante (vedi parametro group_concat_max_len )
Dag

81
E aggiungendo il DISTINCTparametro, non otterrai alcun doppio. ... GROUP_CONCAT(DISTINCT hobbies)
Ludwig,

3
Il mio bisogno era di ottenere TUTTI i dati da una colonna. Non utilizzare la clausola GROUP BY per fare ciò. Esempio: SELEZIONA GROUP_CONCAT (email SEPARATOR ',') DA utenti;
Jonathan Bergeron,

1
Grazie, non sapevo che ci fosse un limite di lunghezza per il gruppo. Ne avevo bisogno per aggirare una lista di mostri che ho generato.
Patrick,

9
Se vuoi ordinare gli hobby nella stringa implosa risultante usa:SELECT person_id, GROUP_CONCAT(hobbies ORDER BY hobbies ASC SEPARATOR ', ') FROM peoples_hobbies GROUP BY person_id
Jan

106

Dai un'occhiata GROUP_CONCATse la tua versione di MySQL (4.1) la supporta. Vedi la documentazione per maggiori dettagli.

Sarebbe simile a:

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

11
Penso che group by 'all'non sia necessario (inoltre indesiderato), perché questo assegna a tutte le stringhe di righe alle quindi confronta le stringhe tra queste righe. Ho ragione?
Krzysiek,

74

Sintassi alternativa per concatenare più righe singole

ATTENZIONE: questo post ti farà venire fame.

Dato:

Mi sono ritrovato a voler selezionare più righe singole, invece di un gruppo, e concatenare un determinato campo.

Supponiamo che tu abbia una tabella di ID prodotto e i loro nomi e prezzi:

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

Quindi hai un po 'di fantasia ajax che elenca questi cuccioli come caselle di controllo.

Il tuo utente affamato di ippopotamo seleziona 13, 15, 16. Nessun dessert per lei oggi ...

Trova:

Un modo per riassumere l'ordine del tuo utente in una riga, con puro mysql.

Soluzione:

Utilizzare GROUP_CONCATcon la INclausola :

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

Quali uscite:

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

Soluzione bonus:

Se vuoi anche il prezzo totale, aggiungi 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: mi scuso se non hai un In-N-Out nelle vicinanze ...


11
Anche se questa è una buona risposta, sembra più una pubblicità che una semplice risposta. Ancora una buona risposta ben formata.
FliiFe,

1
Posso ottenere aiuto stackoverflow.com/q/60278898/11697039 @elbowlobstercowstand
ZUS



25

Nel mio caso avevo una fila di ID, ed era necessario lanciarlo su char, altrimenti il ​​risultato era codificato in formato binario:

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

1
Grazie! Senza CASTavevo valori COME [BLOB - 14 Bytes]nel risultato!
Mel_T

1
Posso ottenere aiuto stackoverflow.com/q/60278898/11697039 @Fedir RYKHTIK
ZUS

16

Utilizzare la variabile di sessione MySQL (5.6.13) e l'operatore di assegnazione come segue

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

allora puoi ottenere

test1,test11

2
è più veloce di GROUP_CONCAT?
jave.web,

1
Ho provato questo sotto PHPMyAdmin con v5.6.17 server MySQL su una descrizione di colonna (varchar (50)) in una prova di tavolo, ma restituisce un campo BLOB per ogni record:SELECT @logmsg := CONCAT_ws(',',@logmsg,description) from test
Gen

14

Ho avuto una query più complicata e ho scoperto che dovevo usare GROUP_CONCATuna query esterna per farlo funzionare:

Query originale:

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

implosa:

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

Spero che questo possa aiutare qualcuno.


9

Per qualcuno che guarda qui come usare GROUP_CONCATcon la subquery - pubblicando questo esempio

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

Quindi GROUP_CONCATdeve essere usato all'interno della sottoquery, non avvolgendolo.


1
Questo era esattamente quello che stavo cercando
bumerang

7

Prova questo:

DECLARE @Hobbies NVARCHAR(200) = ' '

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

2
Questo è quello che ho ottenuto: 'Tipo di istruzione non riconosciuto. (vicino a "DECLARE" nella posizione 0) "
Istiaque Ahmed,

1

abbiamo due modi per concatenare le colonne in MySql

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

O

select group_concat(hobbies) as `Hobbies` from people_hobbies where 1
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.