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
Laufende Summe in SQL – SUM() OVER statt Schleife in der Anwendung
Kontostand nach jeder Buchung, kumulierter Umsatz im Jahr, Restbestand nach jeder Entnahme: Alles dieselbe Frage. Mit einer Fensterfunktion beantwortet die Datenbank sie in einer Abfrage – inklusive gleitendem Durchschnitt.
NULL in SQL – warum COUNT(spalte) lügt und wo die leeren Werte landen
NULL ist kein Wert, sondern die Abwesenheit eines Werts. Deshalb zählt COUNT(spalte) anders als COUNT(*), summiert SUM() an leeren Zeilen vorbei und landen beim Sortieren alle Lücken am selben Ende.
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.