Kann ich mehrere MySQL-Zeilen in einem Feld verketten?

1214

Mit MySQLkann ich so etwas machen wie:

SELECT hobbies FROM peoples_hobbies WHERE person_id = 5;

Mein Output:

shopping
fishing
coding

aber stattdessen möchte ich nur 1 Zeile, 1 Spalte:

Erwartete Ausgabe:

shopping, fishing, coding

Der Grund ist, dass ich mehrere Werte aus mehreren Tabellen auswähle und nach all den Verknüpfungen viel mehr Zeilen habe, als ich möchte.

Ich habe in MySQL Doc nach einer Funktion gesucht und es sieht nicht so aus, als ob die CONCAToder CONCAT_WSFunktionen Ergebnismengen akzeptieren.

Weiß hier jemand, wie man das macht?

Dean Rather
quelle
9
Ich habe gerade eine kleine Demo über die Verwendung von group_concat geschrieben, die für Sie nützlich sein
Marc Giombetti

Antworten:

1739

Sie können verwenden GROUP_CONCAT:

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

Wie Ludwig in seinem Kommentar feststellte , können Sie den DISTINCTOperator hinzufügen , um Duplikate zu vermeiden:

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

Als Jan im angegebenen ihrem Kommentar, können Sie auch die Werte sortieren , bevor sie implodiert mit ORDER BY:

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

Wie Dag in seinem Kommentar feststellte , ist das Ergebnis auf 1024 Byte begrenzt. Um dies zu lösen, führen Sie diese Abfrage vor Ihrer Abfrage aus:

SET group_concat_max_len = 2048;

Natürlich können Sie 2048nach Ihren Wünschen ändern . So berechnen und weisen Sie den Wert zu:

SET group_concat_max_len = CAST(
    (SELECT SUM(LENGTH(hobbies)) + COUNT(*) * LENGTH(', ')
    FROM peoples_hobbies 
    GROUP BY person_id)
    AS UNSIGNED
);
che
quelle
154
Seien Sie sich bewusst sein , der die Begrenzung von 1024 Bytes in der resultierenden Spalte (siehe Parameter group_concat_max_len )
Dag
81
Wenn Sie den DISTINCTParameter hinzufügen , erhalten Sie keine Doppelbilder. ... GROUP_CONCAT(DISTINCT hobbies)
Ludwig
3
Ich musste ALLE Daten aus einer Spalte abrufen. Verwenden Sie dazu nicht die GROUP BY-Klausel. Beispiel: SELECT GROUP_CONCAT (E-Mails SEPARATOR ',') FROM Benutzer;
Jonathan Bergeron
1
Danke, ich wusste nicht, dass es eine maximale Länge für Gruppen gibt. Ich brauchte das, um eine von mir erstellte Monsterliste zu umgehen.
Patrick
9
Wenn Sie in der resultierenden implodiert Zeichenfolge Verwendung sortieren Hobbies wollen:SELECT person_id, GROUP_CONCAT(hobbies ORDER BY hobbies ASC SEPARATOR ', ') FROM peoples_hobbies GROUP BY person_id
Jan
106

Überprüfen Sie, GROUP_CONCATob Ihre MySQL-Version (4.1) dies unterstützt. Weitere Informationen finden Sie in der Dokumentation .

Es würde ungefähr so ​​aussehen:

  SELECT GROUP_CONCAT(hobbies SEPARATOR ', ') 
  FROM peoples_hobbies 
  WHERE person_id = 5 
  GROUP BY 'all';
lpfavreau
quelle
11
Ich denke, das group by 'all'ist nicht notwendig (außerdem unerwünscht), da dies allen Zeilen Zeichenfolge zuweist allund dann Zeichenfolgen zwischen diesen Zeilen vergleicht. Habe ich recht?
Krzysiek
74

Alternative Syntax zum Verketten mehrerer einzelner Zeilen

WARNUNG: Dieser Beitrag macht hungrig.

Gegeben:

Ich wollte mehrere einzelne Zeilen auswählen - anstelle einer Gruppe - und in einem bestimmten Feld verketten.

Angenommen, Sie haben eine Tabelle mit Produkt-IDs sowie deren Namen und Preisen:

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

Dann haben Sie einen ausgefallenen Ajax, der diese Welpen als Kontrollkästchen auflistet.

Ihr Benutzer für hungrige Flusspferde wählt aus 13, 15, 16. Kein Dessert für sie heute ...

Finden:

Eine Möglichkeit, die Bestellung Ihres Benutzers mit reinem MySQL in einer Zeile zusammenzufassen.

Lösung:

Verwenden Sie GROUP_CONCATmit der INKlausel :

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

Welche Ausgänge:

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

Bonuslösung:

Wenn Sie auch den Gesamtpreis möchten, werfen Sie Folgendes ein 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: Entschuldigung, wenn Sie kein In-N-Out in der Nähe haben ...

Ellenbogenlobstercowstand
quelle
11
Obwohl dies eine gute Antwort ist, klingt dies eher nach Werbung als nach reiner Antwort. Immer noch eine gute, gut formulierte Antwort.
FliiFe
1
Kann ich Hilfe bekommen stackoverflow.com/q/60278898/11697039 @elbowlobstercowstand
zus
39

Sie können die maximale Länge des GROUP_CONCATWerts ändern, indem Sie den group_concat_max_lenParameter einstellen .

Details finden Sie in der MySQL-Dokumentation .

pau.moreno
quelle
25

In meinem Fall hatte ich eine Reihe von IDs, und es war notwendig, sie in char umzuwandeln, andernfalls wurde das Ergebnis in ein Binärformat codiert:

SELECT CAST(GROUP_CONCAT(field SEPARATOR ',') AS CHAR) FROM table
Fedir RYKHTIK
quelle
1
Vielen Dank! Ohne hatte CASTich Werte wie [BLOB - 14 Bytes]im Ergebnis!
Mel_T
1
Kann ich Hilfe bekommen stackoverflow.com/q/60278898/11697039 @Fedir RYKHTIK
zus
16

Verwenden Sie die MySQL (5.6.13) -Sitzungsvariable und den Zuweisungsoperator wie folgt

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

dann kannst du bekommen

test1,test11
Shen Liang
quelle
2
ist es schneller als GROUP_CONCAT?
jave.web
1
Getestet habe ich diese unter PHPMyAdmin mit MySQL Server v5.6.17 auf einer Beschreibung Spalte (varchar (50)) in einem Testtisch , aber es gibt ein BLOB - Feld für jeden Datensatz:SELECT @logmsg := CONCAT_ws(',',@logmsg,description) from test
Jan
14

Ich hatte eine kompliziertere Abfrage und stellte fest, dass ich sie GROUP_CONCATin einer äußeren Abfrage verwenden musste, damit sie funktioniert:

Ursprüngliche Abfrage:

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

Implodiert:

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

Hoffe das könnte jemandem helfen.

Alex Bowyer
quelle
9

Für jemanden, der hier sucht, wie man GROUP_CONCATmit Unterabfragen arbeitet - dieses Beispiel posten

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

So GROUP_CONCATmuss in der Unterabfrage verwendet wird, nicht wickeln.

Oleg Abrazhaev
quelle
1
Dies war genau das, wonach ich gesucht hatte
Bumerang
7

Versuche dies:

DECLARE @Hobbies NVARCHAR(200) = ' '

SELECT @Hobbies = @Hobbies + hobbies + ',' FROM peoples_hobbies WHERE person_id = 5;
thejustv
quelle
2
Folgendes habe ich erhalten: 'Nicht erkannter Anweisungstyp. (in der Nähe von "DECLARE" an Position 0) '
Istiaque Ahmed
1

Wir haben zwei Möglichkeiten, Spalten in MySql zu verketten

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

Oder

select group_concat(hobbies) as `Hobbies` from people_hobbies where 1
Raghavendra
quelle