Werte einer Gruppe zu einer Liste zusammenfassen – GROUP_CONCAT in SQLite
Du willst pro Zeile nicht nur zählen, sondern die Werte selbst sehen – etwa alle Tags eines Beitrags als „PHP, SQL, Tipp" in einer Spalte? Genau dafür gibt es GROUP_CONCAT. Ich zeige dir die Grundform, ein eigenes Trennzeichen und wie du Dubletten sortiert loswirst.
COUNT, SUM, AVG kennt jeder – sie verdichten eine Gruppe zu einer Zahl. Aber manchmal willst du die Werte gar nicht ausrechnen, sondern auflisten: alle Tags eines Beitrags, alle Produkte einer Bestellung, alle Mitglieder eines Teams – schön in einer Spalte. Dafür gibt es in SQLite (und ähnlich in MySQL/PostgreSQL) die Aggregatfunktion GROUP_CONCAT.
Die Grundform
Stell dir eine Tabelle beitrag_tags vor, die zu jedem Beitrag mehrere Tag-Zeilen hat:
SELECT beitrag_id, GROUP_CONCAT(tag) AS tags
FROM beitrag_tags
GROUP BY beitrag_id;Ergebnis – eine Zeile pro Beitrag, alle Tags in einer Spalte:
beitrag_id | tags
-----------+------------------
1 | PHP,SQL,Tipp
2 | Kotlin,ComposeOhne zweites Argument trennt SQLite die Werte mit einem Komma.
Eigenes Trennzeichen
Willst du „PHP, SQL, Tipp" mit Leerzeichen oder | als Trenner, gibst du ihn als zweites Argument mit:
SELECT beitrag_id, GROUP_CONCAT(tag, ', ') AS tags
FROM beitrag_tags
GROUP BY beitrag_id;Dubletten raus und sortiert
Tauchen Werte doppelt auf, hilft DISTINCT. Und mit ORDER BY innerhalb des Aufrufs bestimmst du die Reihenfolge in der Liste:
-- doppelte Tags nur einmal
SELECT beitrag_id, GROUP_CONCAT(DISTINCT tag) AS tags
FROM beitrag_tags
GROUP BY beitrag_id;
-- alphabetisch sortiert (SQLite 3.44+)
SELECT beitrag_id, GROUP_CONCAT(tag ORDER BY tag) AS tags
FROM beitrag_tags
GROUP BY beitrag_id;Kleiner Stolperstein: DISTINCT und ein eigenes Trennzeichen lassen sich in SQLite nicht gleichzeitig im selben Aufruf verwenden – für beides zusammen sortierst du vorher in einer Unterabfrage.
Wofür ich das im Alltag nutze
In meinem CMS spare ich mir damit oft eine zweite Abfrage: Statt Tags in einer Schleife nachzuladen, hole ich sie in einem Rutsch als fertige Liste zur Beitragszeile. Ein Aufruf, alle Tags dabei – weniger Code, weniger Datenbank-Roundtrips.
Wenn du ein Projekt mit einer Datenbank hast, die schnell und sauber abfragt statt in tausend Einzelabfragen zu ertrinken, baue ich dir das – meld dich über bymw.de.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
Wie viel mehr als gestern? Differenz zur Vorzeile mit LAG() in SQL
„Wie viele Besucher heute im Vergleich zu gestern?" – der Reflex ist ein Self-Join auf die Vorzeile. Mit der Fensterfunktion LAG() bekommst du den Wert der vorherigen Zeile direkt daneben, ohne die Tabelle ein zweites Mal anzufassen.
WITH RECURSIVE – Kategoriebäume und Kommentar-Threads in einer einzigen Abfrage
Kategorien mit Unterkategorien, Kommentare mit Antworten, Ordner in Ordnern: Die meisten holen sich so etwas mit einer Schleife und einer Abfrage pro Ebene. Eine rekursive CTE holt den ganzen Baum in einem Rutsch – inklusive Tiefe und Pfad.
CREATE VIEW – die Abfrage, die du nur einmal schreibst
Wenn dieselbe 15-zeilige Abfrage an vier Stellen im Code steht, ändert man sie irgendwann an dreien. Eine View gibt ihr einen Namen – danach steht sie nur noch an einer Stelle.