Suchen Sie in MySQL nach "Ganzwortübereinstimmung"

75

Ich möchte eine SQL-Abfrage schreiben, die nach einem Schlüsselwort in einem Textfeld sucht, aber nur, wenn es sich um eine "Ganzwortübereinstimmung" handelt (z. B. wenn ich nach "rid" suche, sollte sie nicht mit "arid" übereinstimmen, sollte es aber Match "a rid".

Ich benutze MySQL.

Glücklicherweise ist die Leistung in dieser Anwendung nicht kritisch, und die Datenbankgröße und die Zeichenfolgengröße sind beide angenehm klein, aber ich würde es vorziehen, dies in SQL zu tun, als in PHP, das es steuert.

Seltsames Denken
quelle

Antworten:

153

Sie können REGEXPdie [[:<:]]und [[:>:]]Wortbegrenzungsmarkierungen verwenden:

SELECT *
FROM table 
WHERE keywords REGEXP '[[:<:]]rid[[:>:]]'

Update für 2020: (aktuell 2018+)

MySQL hat seine RegExp-Engine in Version 8.0.4 aktualisiert, sodass Sie jetzt den " Standard " -Wortgrenzenmarker \ b verwenden müssen:

SELECT *
FROM table 
WHERE keywords REGEXP '\\brid\\b'

Beachten Sie auch, dass Sie dem Backslash entkommen müssen, indem Sie einen zweiten Backslash setzen.

LukeH
quelle
2
Nur eine Anmerkung, Zeichenfolgen mit Sonderzeichen für reguläre Ausdrücke müssen maskiert werden.
Kenston Choi
1
Ein weiteres Problem bei der Einrichtung der Wortgrenzen besteht darin, dass Punkte möglicherweise als Wortgrenzen behandelt werden. Wenn Sie also beabsichtigen, Namen zuzuordnen, funktioniert dies möglicherweise nicht wie erwartet. Wählen Sie 'RC Sproul' Regexp 'R \ .C \.'; / * Gibt 1 zurück * / ... wähle 'RC Sproul' regexp '[[: <:]] R \ .C \. [[:>:]]' / * Gibt 0 zurück * /
Kenston Choi
1
@ LukeH - Danke Mann. Das ist fantastisch. und ich habe RLIKE verwendet. Gibt es einen Unterschied zwischen REGEX und RLIKE?
Shail Paras
1
War nützlich für mich.
Xcoder
2
Und nur ein Hinweis zur Verwendung einer PHP-Variablen in Ihrer MySQL-Abfrage:'[[:<:]]" . $rid . "[[:>:]]'
Stackunderflow
29

Es wurde eine Antwort gefunden, um zu verhindern, dass die klassische Wortgrenze [[::<::]]mit Sonderzeichen kollidiert, z. B. @ # $% ^ & *

Ersetzen..

SELECT *
FROM table 
WHERE keywords REGEXP '[[:<:]]rid[[:>:]]'

Mit diesem..

SELECT *
FROM table 
WHERE keywords REGEXP '([[:blank:][:punct:]]|^)rid([[:blank:][:punct:]]|$)'

Letzteres stimmt überein (Leerzeichen, Tabulator usw.) || (Komma, Klammer usw.) || Anfang / Ende der Zeile. Eine 'fertigere' Wortgrenzenübereinstimmung.

Ricky Boyce
quelle
Dieser Code funktioniert bei mir nicht. Ich Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''([[[:blank:][:punct:]]' at line 3 SQLState: 42000 ErrorCode: 1064verstehe : Irgendwelche Ideen?
Solver42
@ Solver42 Ich habe gerade die obige Abfrage mit MySQL 5.6.21 erneut getestet und es funktioniert wie gewohnt. Versuchen Sie, die erste Klammer von'([[[
Ricky Boyce
Ich habe das versucht, aber den gleichen Fehler bekommen. Dies hat jedoch den Trick getan: ([[: blank:]] | [[: punct:]] | ^) rid ([[: punct:]} | [[: blank:]] | $)
Solver42
5

Sie können likemit dem Platzhalter-Marker die Möglichkeiten abfangen (am Anfang, am Ende, in der Mitte und alleine). So etwas sollte ausreichen:

Wählen Sie bla bla bla, wobei Spalte wie 'rid%' oder Spalte wie '% rid' oder Spalte wie '% rid%' oder column = 'rid'

paxdiablo
quelle
Je nach Situation sollten Sie auch auf Interpunktion achten. Zum Beispiel würde keiner von denen "los" zurückgeben.
Greg Leaver
4
Ich denke die Abfrage ist nicht ausreichend. Was ist mit einem Text wie "rid" oder "(rid)"?
Wenqiang
Gute Antwort, gute Beobachtung, einfache Lösung: Sie können die Abfrage mit benutzerdefinierten Zeilen an die Anforderungen Ihrer Daten anpassen. Fügen Sie beispielsweise weitere Zeilen hinzu, z or column like '% rid, %' or column like 'rid, %'. Oder verwenden Sie die oben beschriebene Regex-Methode.
Stackunderflow
4

Verwenden Sie Regexp mit Wortgrenzen. Wenn Sie jedoch auch eine akzentunempfindliche Suche wünschen, beachten Sie bitte, dass REGEXP ein Einzelbyte-Operator ist. Es lohnt sich also nicht, eine utf8_general_ci-Kollatierung zu haben. Die Übereinstimmung ist nicht akzentunempfindlich.

Geben Sie das Wort so an, wie es die (veraltete) PHP-Funktion sql_regcase () getan hat, damit sowohl der Akzent unempfindlich als auch das gesamte Wort übereinstimmen.

Eigentlich:

  • Mit utf8_general_ci können Sie eine Suche nach Gleichheit (WHERE-Feld = Wert) und ohne Akzent durchführen, jedoch keine vollständige Wortübereinstimmung angeben (Wortgrenzenmarkierungen nicht erkannt).

  • LIKE ermöglicht Ihnen die Suche ohne Berücksichtigung von Groß- und Kleinschreibung und Akzent, Sie müssen jedoch alle Kombinationen möglicher Zeichen für Wortgrenzen manuell angeben (Wortgrenzenmarkierungen werden nicht erkannt).

  • Wortgrenzen [[: <:]] und [[:>:]] werden in REGEXP unterstützt, bei dem es sich um Einzelbytefunktionen handelt. Führen Sie daher keine akzentunempfindliche Suche durch.

Die Lösung besteht darin, REGEXP mit Wortgrenzen zu verwenden und das Wort so zu ändern, wie es sql_regcase tut.

Wird auf http://www.nonsolodiete.it verwendet

Marco Marsala
quelle
1
select * from table where Locate('rid ', FieldToSearch) > 0 
      or Locate(' rid', FieldToSearch) > 0

Auf diese Weise können Sie herausfinden, wo ein Leerzeichen vor oder nach dem Leerzeichen steht. Sie können den Ansatz erweitern, um dies zu berücksichtigen.,?! und so weiter, nicht elegant, aber einfach.

MrTelly
quelle
1

Dies ist die beste Antwort, die ich mir bisher ausgedacht habe:

SELECT * FROM table 
WHERE keywords REGEXP '^rid[ $]' OR keywords REGEXP ' rid[ $]'

Ich hätte es vereinfacht, um:

SELECT *
FROM table
WHERE keywords REGEXP '[^ ]rid[ $]'

aber [^] hat eine spezielle Bedeutung von "NICHT ein Leerzeichen" anstelle von "Zeilenanfang oder Leerzeichen".

Wie vergleicht sich REGEXP mit mehreren LIKE-Bedingungen? (Nicht, dass die Leistung in dieser App wichtig ist.)

Seltsames Denken
quelle
2
Wenn du es geschafft hättest [^], würde der zweite funktionieren. ^ ist nur "nicht", wenn es das erste Zeichen in einer Menge ist, IIRC.
Travis Jensen
Ich frage mich, ob SQL REGEXP ein "Wortgrenzen" -Feld wie Perl \ b hat. Das würde Leerzeichen, Interpunktion usw. behandeln
Andy White
@Andy, MySql verwendet [[: <:]] und [[:>:]] als Wortgrenzmarkierungen.
LukeH
@Oddthinking, Wortgrenzenmarkierungen sind wahrscheinlich das, was Sie verwenden sollten. Siehe meine Antwort für ein Beispiel.
LukeH
1
Oder Sie können es schreiben als: SELECT * FROM Tabelle WHERE Schlüsselwörter REGEXP '(^ |) rid (| $)'
Kenston Choi