Ich wünschte ich hätte im Laufe meiner Karriere schon viel früher diesen Weg gefunden, wie man in MySQL kommagetrennte Werte  filtern kann.

Der Fall

Sobald man sich durch die MySQL Datenbankstrukturen von Fremdsystemen arbeitet kommt man früher oder später an dem Punkt wo man in einem Tabellenfeld kommagetrennte Werte vorfindet. In einer perfekten Welt sollte es so einen Fall gar nicht geben, sondern diese Werte sollten in einer separaten Verknüpfungstabelle mit indizierten Fremdschlüsseln abgelegt sein.

Aber in unserer Welt gibt es organisch gewachsene Systeme, in denen vielleicht anfangs nur ein einzelner Wert in diesem Feld stand. Und dann wurde eventuell schnell einmal eine „Übergangslösung“ gebaut, in der es notwendig war in das Feld dann doch mehr als nur einen Wert zu speichern.

Ein klassische Fall ist zum Beispiel die Datenstruktur in diversen Diskussionsforen, bei der es in der User-Tabelle ein Feld für die Usergroup gibt. In diesem Feld stehen dann die IDs von mehreren Benutzergruppen sobald im Laufe der Entwicklung festgestellt wird, dass eine einzelne Gruppe pro User nicht mehr ausreicht.

Lösungsansätze

Angenommen in dem Feld liegt uns folgender Inhalt vor:

1,5,7,12,17,21

Und nun möchten wir prüfen ob der Wert 1 in diesem Feld vorhanden ist, also ob z.B. der Benutzer der Administratorengruppe angehört (wenn diese die ID 1 hat). Der erste Lösungsansatz für eine Anweisung in MySQL ohne groß zu überlegen wäre ein LIKE. Das kennt man ja von VARCHAR und TEXT Feldern.

SELECT * FROM user WHERE usergroup LIKE '%1%';

Aber das liefert uns nicht nur user mit dem Wert 1 sondern auch die mit den Werten 12, 17 und 21, denn auch hier ist eine 1 im String enthalten. Also wie wäre es mit:

SELECT * FROM user WHERE usergroup LIKE '%1,%';

Jap, in diesem speziellen Fall bekäme man das gewünschte Ergebnis. Aber was wäre, wenn die Gruppen IDs einmal neu in anderer Reihenfolge gespeichert werden? Zum Beispiel:

5,17,12,1,7,21,36

Auf einmal bekommt man auch die User mit der 17, 12 und 21. Das ist also auch viel zu ungenau. Wenn das System bzw. der programmierer etwas schlauer war, hat er darauf geachtet jeden Wert mit einem Komma zu umschließen, also zum Beispiel:

,5,17,12,1,7,21,36,

In diesem Fall können wir uns darauf verlassen, dass wir immer den Wert mit einem Komma vorne und hinten suchen können, also:

SELECT * FROM user WHERE usergroup LIKE '%,1,%';

Aber so eine Situation findet man eher selten vor. Also was tun? Man könnte per Programmcode (PHP, Python, etc) natürlich alle User prüfen, die Werte an den Kommata splitten und jeden einzelnen Wert „auf 1“ prüfen, aber das ist weder elegant noch sonderlich performant.

Die Lösung

Wenn man sich einmal die MySQL Dokumentation anschaut, dann findet man dort einige sehr praktische Funktionen. Eine davon lautet ‚FIND_IN_SET()‘. Und diese  Funktion tut genau das, was wir brauchen, nämlich einen Wert in einem Feld mit kommagetrennten Werten finden. Als ersten Patrameter nimmt FIND_IN_SET den gesuchten Wert entgegen und als zweiten Parameter die Liste, die durchsucht werden soll. Das kann jeweils auch ein Tabellenfeld sein. Folgende Anweisung liefert uns damit das gewünschte Ergebnis aus dem Beispiel oben:

SELECT * FROM user WHERE FIND_IN_SET('1', usergroup);

So einfach kann es sein.