neunzehn83.de

Ein Mann, ein Blog, kein Plan.

MySQL's GROUP_CONCAT()

Die GROUP_CONCAT-Funktion von MySQL ist eine tolle Erweiterung zu GROUP BY.  Insbesondere wenn man es mit one-to-many oder many-to-many Beziehungen zu tun hat. GROUP_CONCAT() ist seit der Version 4.1 Bestandteil von MySQL.

Beispiel: Personen haben Hobbys. Die Personen werden in der Personen-Tabelle mit dem Namen (name) und einer eindeutigen ID (person_id) gespeichert. Die zugehörigen Hobbys stehen in der Hobbys-Tabelle. Die Hobbys haben ebenfalls eine fortlaufende ID (hobby_id). Der Name des Hobbys steht in der Spalte hobby, die Verknüpfung zur Person wird über die person_id-Spalte hersgestellt.

mysql> SELECT * FROM personen;
+-----------+-------+
| person_id | name  |
+-----------+-------+
|         1 | Peter |
|         2 | Paul  |
+-----------+-------+

mysql> SELECT * FROM hobbys;
+----------+-----------+-----------+
| hobby_id | person_id | hobby     |
+----------+-----------+-----------+
|        1 |         1 | Schwimmen |
|        2 |         1 | Reiten    |
|        3 |         2 | Radfahren |
+----------+-----------+-----------+

Da eine Person mehrere Hobbys haben, und das selbe Hobby von mehreren Personen ausgeübt werden kann, wäre hier eine many-to-many Beziehung mit extra Join-Tabelle sinnvoller. Der Einfachheit halber belassen wir es aber bei zwei Tabellen. Die Funktionsweise von GROUP_CONCAT() ist in beiden Fällen sowieso die selbe.

Peter hat also die Hobbys "Schwimmen und Reiten", Paul hat das Hobby Radfahren. Um jetzt mit PHP eine einfache Tabelle auszugeben, in der jeder Name mit den jeweiligen Hobbys aufgelistet wird, könnte man zunächst alle Namen holen, und dann pro Reihe die jeweiligen Hobbys in einem separatem Query. Das würde aber bedeuten, dass wir für n Datensätze n+1 Queries brauchen. Viel zu viel!

Packt man das alles in ein einziges  Query, und joint die Hobbys-Tabelle, taucht im Result der Peter leider doppelt auf. Auch doof...

Abhilfe schafft die GROUP_CONCAT()-Funktion in Verbindung mit einem GROUP BY. GROUP_CONCAT() konkateniert (=verbindet) alle Werte einer Gruppe zu einem String. Null-Werte werden ignoriert. Standardmäßig wird das ganze Komma-getrennt.

SELECT
    p.name
    , GROUP_CONCAT(h.hobby SEPARATOR ', ') AS hobbys
FROM
    personen p
LEFT JOIN
    hobbys h ON h.person_id = p.person_id
GROUP BY
    p.person_id

Mit der Angabe von SEPARATOR innerhalb der GROUP_CONCAT-Funktion trennen wir die einzelnen Hobbys zusätzlich mit einer Leertaste. Ergebnis:

+-------+-------------------+
| name  | hobbys            |
+-------+-------------------+
| Peter | Schwimmen, Reiten |
| Paul  | Radfahren         |
+-------+-------------------+

Perfekt! Für die besonders aufmerksamen Leser gibt's hier nochmals das komplette Beispiel als SQL-File zum auswendig lernen ;)

Geschrieben am Dienstag, 23. Februar 2010 und abgelegt unter Webtechnik.