MySQL FIND_IN_SET erklärt: Wie man kommagetrennte Werte korrekt durchsucht

目次

1. Einführung

Die Herausforderung, kommagetrennte Daten in MySQL zu durchsuchen

Wenn Sie mit Datenbanken arbeiten, kann es vorkommen, dass mehrere Werte in einer einzigen Spalte durch Kommas getrennt gespeichert werden. Beispielsweise kann eine Spalte einen String wie "1,3,5" enthalten, und Sie möchten nur die Datensätze extrahieren, die den Wert „3“ enthalten.

In solchen Fällen liefert der Standard‑=‑Operator oder die IN‑Klausel oft nicht das erwartete Ergebnis. Das liegt daran, dass ein kommagetrennter String als ein einziger String‑Wert behandelt wird, sodass Vergleiche gegen den gesamten String und nicht gegen einzelne Elemente darin ausgewertet werden.

Was ist die FIND_IN_SET‑Funktion?

In solchen Situationen ist die MySQL‑Funktion FIND_IN_SET sehr nützlich.
Sie ermöglicht es Ihnen, einfach zu bestimmen, ob ein bestimmter Wert in einem kommagetrennten String vorkommt.

Zum Beispiel, betrachten Sie die folgende SQL‑Anweisung:

SELECT * FROM users WHERE FIND_IN_SET('3', favorite_ids);

In dieser Abfrage können Sie Datensätze extrahieren, bei denen der kommagetrennte String in der Spalte favorite_ids (z. B. "1,2,3,4") den Wert „3“ enthält.

Zweck dieses Artikels und Zielgruppe

Dieser Artikel erklärt, wie man die FIND_IN_SET‑Funktion von den Grundlagen an klar und strukturiert verwendet. Von der Basissyntax über praktische Beispiele, Vergleiche mit anderen Suchmethoden, wichtige Überlegungen bis hin zu FAQs – dieser Leitfaden liefert praktisches Wissen für die reale Entwicklung.

Der Artikel richtet sich an:

  • Web‑Engineers und Backend‑Entwickler, die regelmäßig MySQL einsetzen
  • Entwickler, die mit bestehenden Systemen arbeiten, die kommagetrennte Daten speichern
  • SQL‑Anfänger, die Schwierigkeiten mit Teil‑Übereinstimmungen und wertbasierten Suchen haben

2. Grundsyntax und Verhalten der FIND_IN_SET‑Funktion

Syntax von FIND_IN_SET

FIND_IN_SET ist eine MySQL‑Funktion, die prüft, ob ein bestimmter Wert in einem kommagetrennten String vorkommt. Die Grundsyntax lautet wie folgt:

FIND_IN_SET(search_value, comma_separated_string)

Beispiel:

SELECT FIND_IN_SET('3', '1,2,3,4'); -- Result: 3

In diesem Beispiel, da „3“ an dritter Stelle steht, gibt die Funktion den numerischen Wert 3 zurück.

Rückgabewert‑Regeln

Die FIND_IN_SET‑Funktion verhält sich nach den folgenden Regeln:

ConditionResult
The search value exists in the listIts position in the list (starting from 1)
The search value does not exist0
Either argument is NULLNULL

Beispiel (Rückgabe der Position)

SELECT FIND_IN_SET('b', 'a,b,c'); -- Result: 2

Beispiel (Wert nicht gefunden)

SELECT FIND_IN_SET('d', 'a,b,c'); -- Result: 0

Beispiel (NULL enthalten)

SELECT FIND_IN_SET(NULL, 'a,b,c'); -- Result: NULL

Beispielhafte Verwendung in einer WHERE‑Klausel

Am häufigsten wird diese Funktion zum Filtern innerhalb einer WHERE‑Klausel eingesetzt.

SELECT * FROM users WHERE FIND_IN_SET('admin', roles);

In diesem Beispiel werden nur Zeilen zurückgegeben, bei denen die Spalte roles den String „admin“ enthält. Enthält die Spalte einen Wert wie "user,editor,admin", wird ein Treffer erzielt.

Wichtige Hinweise zu Zahlen und Strings

FIND_IN_SET führt Vergleiche als Strings durch, was bedeutet, dass es sich wie folgt verhält:

SELECT FIND_IN_SET(3, '1,2,3,4');     -- Result: 3
SELECT FIND_IN_SET('3', '1,2,3,4');   -- Result: 3

Obwohl die Funktion sowohl mit numerischen als auch mit String‑Werten funktioniert, können unklare Datentypen zu unerwartetem Verhalten führen. Daher ist es bewährte Praxis, Werte nach Möglichkeit explizit als Strings zu behandeln.

3. Praktische Beispiele

Suche in einer Spalte, die kommagetrennte Strings speichert

In realen Systemen kommt es häufig vor, dass mehrere Werte (z. B. IDs oder Berechtigungen) in einer einzigen Spalte als kommagetrennter String abgelegt werden. Betrachten Sie zum Beispiel die folgende users‑Tabelle.

idnamefavorite_ids
1Taro1,3,5
2Hanako2,4,6
3Jiro3,4,5

Wenn Sie „Benutzer, die 3 enthalten“ abrufen möchten, ist die FIND_IN_SET‑Funktion äußerst praktisch.

SELECT * FROM users WHERE FIND_IN_SET('3', favorite_ids);

Die Ausführung dieses SQL‑Befehls liefert die Datensätze für „Taro“ und „Jiro“.

Funktioniert einwandfrei, selbst wenn Werte numerisch aussehen

Selbst wenn favorite_ids scheinbar Zahlen enthält, führt FIND_IN_SET zeichenbasierte Vergleiche durch, daher ist es am sichersten, das Argument als Zeichenkette in Anführungszeichen zu übergeben.

-- OK
SELECT * FROM users WHERE FIND_IN_SET('5', favorite_ids);

-- Works, but strictly speaking not recommended
SELECT * FROM users WHERE FIND_IN_SET(5, favorite_ids);

Um Abfragen lesbar und das Verhalten vorhersehbar zu halten, wird empfohlen, den Wert explizit als Zeichenkette anzugeben.

Dynamische Suchen (Platzhalter und Variablen)

Beim dynamischen Erzeugen von SQL aus einer Webanwendung ist es üblich, Variablen oder Bind‑Parameter zu verwenden.

Wenn Sie eine MySQL‑Variable verwenden, sieht das so aus:

SET @target_id = '3';
SELECT * FROM users WHERE FIND_IN_SET(@target_id, favorite_ids);

Beim Binden aus einer Anwendungsschicht (wie PHP, Python oder Node.js) können Sie dies ähnlich mit Platzhaltern handhaben.

Wie man die Suche nach mehreren Werten handhabt

Leider kann FIND_IN_SET nur nach einem Wert gleichzeitig suchen.
Wenn Sie Datensätze abrufen möchten, die „3 oder 4“ enthalten, müssen Sie dies mehrmals mit OR schreiben.

SELECT * FROM users
WHERE FIND_IN_SET('3', favorite_ids) OR FIND_IN_SET('4', favorite_ids);

Wenn die Bedingungen komplexer werden, sollten Sie entweder das SQL in Ihrer Anwendung dynamisch erstellen oder eine Migration zu einer normalisierten Tabellenstruktur in Betracht ziehen.

4. Vergleich von FIND_IN_SET mit anderen Suchmethoden

Häufige Alternativen: IN und LIKE

In MySQL können Sie neben FIND_IN_SET auch die IN‑Klausel oder die LIKE‑Klausel sehen, die verwendet werden, um zu prüfen, ob ein Wert enthalten ist. Jede Methode verhält sich jedoch anders, und die falsche Verwendung kann zu falschen Abfrageergebnissen führen.

Hier klären wir, wie sie sich von FIND_IN_SET unterscheiden und wann jede Vorgehensweise zu verwenden ist.

Vergleich mit der IN‑Klausel

Die IN‑Klausel wird typischerweise verwendet, um zu prüfen, ob ein Wert einem von mehreren konstanten Werten entspricht.

-- Example of IN (this does NOT search inside "favorite_ids" for the value 3)
SELECT * FROM users WHERE favorite_ids IN ('3');

In diesem Fall werden nur Datensätze zurückgegeben, bei denen favorite_ids eine exakte Übereinstimmung mit „3“ ist. Das bedeutet, Werte wie „1,3,5“ passen nicht – nur eine Zeile, bei der der Spaltenwert exakt „3“ ist, wird zurückgegeben.

Im Gegensatz dazu prüft FIND_IN_SET die Position eines Elements innerhalb einer kommagetrennten Liste, sodass Sie Datensätze, die „3“ enthalten, genau so abrufen können:

SELECT * FROM users WHERE FIND_IN_SET('3', favorite_ids);

Wichtige Nutzungsempfehlung:

  • IN : Verwenden Sie sie mit normalisierten Tabellen (z. B. SELECT * FROM posts WHERE category_id IN (1, 3, 5) )
  • FIND_IN_SET : Verwenden Sie sie mit denormalisierten, kommagetrennten Zeichenketten

Vergleich mit der LIKE‑Klausel

Technisch können Sie LIKE für Teilübereinstimmungen verwenden, aber es birgt wichtige Fallstricke.

-- A common mistake with LIKE
SELECT * FROM users WHERE favorite_ids LIKE '%3%';

Diese Abfrage bedeutet nicht wirklich „enthält den Wert 3“ – sie trifft auf jede Zeichenkette zu, die das Zeichen „3“ enthält, was dazu führen kann, dass fälschlicherweise „13“, „23“ oder „30“ übereinstimmen.

Damit ist es unmöglich, zuverlässig zu erkennen, ob 3 als eigenständiger Wert existiert.

Wichtige Nutzungsempfehlung:

  • LIKE : Nützlich für unscharfe Textsuche, erkennt jedoch keine kommagetrennten Grenzen
  • FIND_IN_SET : Prüft genau, ob ein eigenständiger Wert in kommagetrennten Listen vorkommt

Leistungsunterschiede

MethodUses IndexSearch TargetSpeed
INYesNumber or single value◎ Very fast
LIKEDepends on patternText scan△ Can become slow depending on conditions
FIND_IN_SETNoFull scan× May be slow

Insbesondere kann FIND_IN_SET keine Indizes nutzen und löst häufig vollständige Tabellenscans aus. Wenn Sie mit großen Datensätzen arbeiten, sollten Sie das Schema möglicherweise überdenken.

5. Wichtige Hinweise und bewährte Verfahren

Nicht kompatibel mit Werten, die Kommas enthalten

Die FIND_IN_SET-Funktion geht von einer einfachen, durch Kommas getrennten Liste von Werten aus. Daher verhält sich die Funktion nicht wie beabsichtigt, wenn ein einzelnes Element in der Liste selbst ein Komma enthält.

Falsches Beispiel:

SELECT FIND_IN_SET('1,2', '1,2,3,4'); -- Result: 1

Die Verwendung auf diese Weise kann zu falschen Treffern führen, weil die gesamte Zeichenkette unsachgemäß ausgewertet wird.
Sie sollten diese Funktion nur verwenden, wenn Sie sicherstellen können, dass einzelne Werte keine Kommas enthalten.

Leistungsbedenken

Da FIND_IN_SET keine Indizes nutzen kann, führt es einen vollständigen Tabellenscan durch. Infolgedessen kann die Abfrageleistung bei großen Tabellen erheblich sinken.

Umgehungen:

  • Anstatt kommagetrennte Werte zu speichern, normalisieren Sie die Beziehung und verwalten sie in einer separaten Tabelle.
  • In leistungskritischen Umgebungen sollten Sie temporäre Tabellenerweiterungen oder JOIN-basierte Strategien in Betracht ziehen.

Zum Beispiel, wenn Sie eine Zwischentabelle wie user_favorites erstellen, können Sie Indizes für schnellere Suchen nutzen:

SELECT users.*
FROM users
JOIN user_favorites ON users.id = user_favorites.user_id
WHERE user_favorites.favorite_id = 3;

Lesbarkeit und Wartbarkeit

Obwohl FIND_IN_SET praktisch erscheinen mag, hat es mehrere Nachteile:

  • Abfragen sind nicht intuitiv (sie geben Positionswerte zurück)
  • Das Hinzufügen oder Entfernen von Werten ist umständlich
  • Die Datenintegrität ist schwer durchzusetzen (mehrere Bedeutungen in einer einzigen Spalte)

Daher ist es, wenn Wartbarkeit und Datenintegrität wichtig sind, die Überarbeitung des Schemas selbst oft die beste Vorgehensweise.

Wenn Sie FIND_IN_SET verwenden müssen

Es gibt Situationen, in denen Sie keine andere Wahl haben, als mit kommagetrennten Spalten zu arbeiten – etwa bei Altsystemen oder Drittanbieterprodukten. In solchen Fällen sollten Sie die folgenden Vorsichtsmaßnahmen beachten:

  • Zuerst andere Filterbedingungen anwenden, um den Suchbereich zu reduzieren
  • Formatierungsfehler wie doppelte Kommas oder führende/abschließende Leerzeichen verhindern
  • Zusätzliche Verarbeitung nach Möglichkeit in der Anwendungsschicht durchführen

6. Häufig gestellte Fragen (FAQ)

Kann FIND_IN_SET Indizes verwenden?

Nein, FIND_IN_SET kann keine Indizes verwenden. Intern teilt und bewertet es die Zeichenkette, sodass es nicht von MySQLs Indexoptimierung profitiert.

Infolgedessen kann die Verwendung auf großen Tabellen die Abfrageleistung verlangsamen. Für leistungskritische Systeme sollten Sie das Schema neu entwerfen oder die Daten normalisieren.

Funktioniert es korrekt mit gemischten Zahlen und Zeichenketten?

Im Allgemeinen ja – beachten Sie jedoch, dass Vergleiche als Zeichenketten durchgeführt werden. Wenn numerische und Zeichenkettenwerte gemischt werden, kann unerwartetes Verhalten auftreten.

Zum Beispiel geben beide der folgenden Beispiele eine Übereinstimmung für 3 zurück:

SELECT FIND_IN_SET(3, '1,2,3,4');     -- Result: 3
SELECT FIND_IN_SET('3', '1,2,3,4');   -- Result: 3

In Fällen wie FIND_IN_SET('03', '01,02,03') kann die Formatierung mit führenden Nullen das Matching-Verhalten beeinflussen.
Am sichersten ist es, die Werteformatierung zu standardisieren.

Wie kann ich nach mehreren Werten gleichzeitig suchen?

Da FIND_IN_SET nur einen einzelnen Suchwert akzeptiert, müssen Sie, wenn Sie nach Datensätzen suchen wollen, die „3 oder 4“ enthalten, es mehrmals mit OR aufrufen:

SELECT * FROM users
WHERE FIND_IN_SET('3', favorite_ids)
   OR FIND_IN_SET('4', favorite_ids);

Wenn die Bedingungen komplexer werden, sollten Sie in Erwägung ziehen, SQL dynamisch in der Anwendungsschicht zu erstellen oder zu einer normalisierten Tabellenstruktur zu migrieren.

FIND_IN_SET verursacht Leistungsprobleme. Was soll ich tun?

Die folgenden Strategien sind wirksam:

  • Auf ein normalisiertes Tabellendesign umsteigen
  • Zuerst Filterbedingungen anwenden, um den Suchbereich zu reduzieren
  • Nur bei kleinen Datensätzen verwenden
  • Eine Migration zu strukturierten Formaten wie Volltextsuche oder JSON-Datentypen in Betracht ziehen

Moderne MySQL-Versionen unterstützen JSON-Datentypen. Zum Beispiel, wenn Sie die Spalte roles als JSON-Array verwalten, können Sie JSON_CONTAINS() für flexible und effiziente Suchen verwenden.

Wird FIND_IN_SET in Zukunft veraltet sein?

Seit MySQL 8.0 ist FIND_IN_SET nicht offiziell veraltet. Allerdings werden denormalisierte Datenstrukturen (kommagetrennte Spalten) nicht empfohlen, sodass die praktische Nutzung dieser Funktion voraussichtlich im Laufe der Zeit abnehmen wird.

Beim Neugestalten Ihrer Datenbank ist es ideal, normalisierte Strukturen oder JSON-basierte Designs zu übernehmen.

7. Fazit

Überprüfung der Funktionen und Vorteile von FIND_IN_SET

Die Funktion FIND_IN_SET ist außerordentlich nützlich in MySQL beim Durchsuchen kommagetrennter Zeichenketten. Sie ist besonders hilfreich, wenn Sie Datensätze extrahieren müssen, die einen bestimmten Wert in einer einzelnen Spalte mit mehreren Werten enthalten.

Mit ihrer einfachen Syntax ermöglicht sie Prüfungen auf einzelne Wertübereinstimmungen, die mit den Klauseln LIKE oder IN nur schwer exakt zu erreichen sind. Diese Fähigkeit, einzelne Elemente in einer kommagetrennten Liste zu erkennen, ist ihre größte Stärke.

Wichtige Überlegungen bei der Verwendung

Gleichzeitig gibt es mehrere Einschränkungen und wichtige Überlegungen, sodass sie nicht ohne sorgfältiges Nachdenken übermäßig verwendet werden sollte:

  • Indizes können nicht verwendet werden (was die Suche verlangsamen kann)
  • Nicht kompatibel mit Werten, die Kommas enthalten
  • Geht von einer denormalisierten Struktur aus
  • Unterstützt nur Ein‑Wert‑Suchen (mehrere Suchen erfordern OR ‑Bedingungen)

Das Verständnis dieser Eigenschaften ist entscheidend, um die Funktion angemessen zu nutzen.

Wann Sie sie verwenden sollten — und wann nicht

SituationShould You Use It?Reason
Small dataset, infrequent searches✅ YesEasy to implement and low development cost
Dependent on a legacy system structure✅ Use selectivelyUseful when refactoring is difficult
Large dataset, high-frequency access❌ Not recommendedPerformance degradation becomes significant
Schema can be normalized❌ AvoidJOINs or intermediate tables are more efficient

Wie man das in der Praxis anwendet

  • Betrachten Sie es als flexibles Werkzeug, um innerhalb bestehender Datenbankstrukturen zu arbeiten
  • Nutzen Sie es als Referenzpunkt bei der Entscheidung, ob künftig ein normalisiertes Datenmodell eingeführt werden soll
  • Anstatt es als Schnelllösung zu verwenden, sollten Sie genau verstehen, was die Funktion tatsächlich bewirkt

Für Entwickler, die Wartbarkeit und Lesbarkeit priorisieren, ist es am besten, diese Funktion als etwas zu betrachten, das Sie „vorübergehend verwenden – aber schließlich ablegen“ sollten.