PostgreSQL: So erstellen Sie eine Abfrage ohne Berücksichtigung der Groß- und Kleinschreibung

338

Gibt es eine Möglichkeit, Abfragen ohne Berücksichtigung der Groß- und Kleinschreibung in PostgreSQL zu schreiben? Ich möchte beispielsweise, dass die folgenden drei Abfragen dasselbe Ergebnis liefern.

SELECT id FROM groups where name='administrator'

SELECT id FROM groups where name='ADMINISTRATOR'

SELECT id FROM groups where name='Administrator'
Jame
quelle
Wenn citext mit Ihrer Postgres-Installation geliefert wird, versuchen Sie es mit citext type. Es ist Text ohne
Berücksichtigung
2
Für Neulinge in dieser Frage enthält dieser Link zur offiziellen Postgres-Dokumentation alle hier gegebenen Antworten sowie einige andere Optionen.
Parthian Shot
Sir ordnet die akzeptierte Antwort bitte der von @Arun zu. Es ist viel weniger kompliziert und zieht nach dem Auftragen keine Probleme auf sich.
Zeliboba

Antworten:

451

Verwenden Sie die LOWER- Funktion, um die Zeichenfolgen vor dem Vergleich in Kleinbuchstaben umzuwandeln.

Versuche dies:

SELECT id 
  FROM groups
 WHERE LOWER(name)=LOWER('Administrator')
Chandu
quelle
92
Es ist wichtig zu beachten, dass die Verwendung von LOWER (oder einer beliebigen Funktion) für die Prädikatspalten - in diesem Fall "Name" - dazu führt, dass keine Indizes mehr gesucht werden können. Wenn es sich um eine große oder häufig abgefragte Tabelle handelt, kann dies zu Problemen führen. Die Sortierung ohne Berücksichtigung der Groß- und Kleinschreibung, der Citext oder ein funktionsbasierter Index verbessern die Leistung.
Jordanien
108
Oder erstellen Sie einfach einen Index wie folgt: CREATE INDEX idx_groups_name ON groups lower (name);
Daniel
19
Geben varchar_pattern_opsSie außerdem an, ob der Index mit LIKE 'xxx%'Abfragen arbeiten soll, z CREATE INDEX ix_groups_name ON groups (lower(name) varchar_pattern_ops).
Sayap
10
Die Verwendung des ILIKE-Operators (wie in anderen Antworten unten gezeigt) ist ein einfacherer Ansatz, obwohl dies die am häufigsten gewählte Antwort ist.
Ryan
5
Wenn Sie die Kommentare hier durchgehen, schlagen viele Vorschläge hier vor ILIKE: Es wird funktionieren but with slow response. Um einen schnellen Zugriff auf Tabellen zu erhalten, die auf den Ergebnissen von Berechnungen basieren, empfehle ich jedem, der dies nur überprüft, die akzeptierte Antwort zu verwenden. Weitere Details finden Sie hier und hier
Afolabi Olaoluwa Akinwumi
230

mit ILIKEanstelle vonLIKE

SELECT id FROM groups WHERE name ILIKE 'Administrator'
Mohammad Reza Norouzi
quelle
1
Beachten Sie, dass der ILIKERuhezustand bei Verwendung in Spring Boot nicht unterstützt wird.
AnT
@AnT funktioniert es mit org.hibernate.dialect.PostgreSQL94Dialectund Spring Boot 2.0.6.RELEASE. Aber IntelliJ beschwert sich darüber.
Samintha Kaveesh
134

Der gebräuchlichste Ansatz besteht darin, die Suchzeichenfolge und die Daten entweder in Klein- oder Großbuchstaben zu schreiben. Damit sind jedoch zwei Probleme verbunden.

  1. Es funktioniert in Englisch, aber nicht in allen Sprachen. (Vielleicht nicht einmal in den meisten Sprachen.) Nicht jeder Kleinbuchstabe hat einen entsprechenden Großbuchstaben. Nicht jeder Großbuchstabe hat einen entsprechenden Kleinbuchstaben.
  2. Wenn Sie Funktionen wie Lower () und Upper () verwenden, erhalten Sie einen sequentiellen Scan. Es können keine Indizes verwendet werden. Auf meinem Testsystem dauert die Verwendung von lower () etwa 2000-mal länger als eine Abfrage, die einen Index verwenden kann. (Testdaten haben etwas mehr als 100.000 Zeilen.)

Es gibt mindestens drei weniger häufig verwendete Lösungen, die möglicherweise effektiver sind.

  1. Verwenden Sie das citext-Modul , das hauptsächlich das Verhalten eines Datentyps ohne Berücksichtigung der Groß- und Kleinschreibung nachahmt. Nachdem Sie dieses Modul geladen haben, können Sie einen Index erstellen, bei dem die Groß- und Kleinschreibung nicht berücksichtigt wird CREATE INDEX ON groups (name::citext);. (Aber siehe unten.)
  2. Verwenden Sie eine Sortierung ohne Berücksichtigung der Groß- und Kleinschreibung. Dies wird festgelegt, wenn Sie eine Datenbank initialisieren. Wenn Sie eine Sortierung ohne Berücksichtigung der Groß- und Kleinschreibung verwenden, können Sie nahezu jedes Format aus dem Clientcode akzeptieren und erhalten dennoch nützliche Ergebnisse. (Es bedeutet auch, dass Sie keine Groß- und Kleinschreibung abfragen können. Duh.)
  3. Erstellen Sie einen Funktionsindex. Erstellen Sie mit CREATE INDEX ON groups (LOWER(name));. Nachdem Sie dies getan haben, können Sie den Index mit Abfragen wie nutzen SELECT id FROM groups WHERE LOWER(name) = LOWER('ADMINISTRATOR');, oder SELECT id FROM groups WHERE LOWER(name) = 'administrator';Sie müssen daran denken , LOWER () zu verwenden.

Das citext-Modul bietet keinen Datentyp, bei dem die Groß- und Kleinschreibung nicht berücksichtigt wird. Stattdessen verhält es sich so, als ob jede Zeichenfolge in Kleinbuchstaben geschrieben wäre. Das heißt, es verhält sich so, als hätten Sie lower()jede Zeichenfolge aufgerufen , wie in Nummer 3 oben. Der Vorteil ist, dass Programmierer nicht daran denken müssen, Zeichenfolgen in Kleinbuchstaben zu schreiben. Sie müssen jedoch die Abschnitte "Verhalten beim Vergleichen von Zeichenfolgen" und "Einschränkungen" in den Dokumenten lesen, bevor Sie sich für die Verwendung von citext entscheiden.

Mike Sherrill 'Cat Recall'
quelle
1
Über # 1: Es sollte kein Problem sein, da es sich um zwei verschiedene Zeichenfolgen handelt (denken Sie daran, wie col = 'a'und col = 'b'). Zu # 2: Wie Sie sagten, können Sie einen Index für einen Ausdruck erstellen, sodass dies kein wirkliches Problem darstellt. Aber ich stimme Ihnen zu, dass das Ändern der Sortierung höchstwahrscheinlich die beste Lösung ist.
Vincent Savard
5
Kann mir jemand sagen, welche Kollatierungen ohne Berücksichtigung der Groß- und Kleinschreibung in PostgreSQL integrierte Kollatierungen sind? Ich sehe dies als Option, kann aber nichts über eine Sortierung ohne Berücksichtigung der Groß- und Kleinschreibung für Postgres im Internet finden.
Khorvat
1
@ AnupShah: Nein, das sage ich nicht. Ich verwende PostgreSQL nicht unter Windows. In den 9.4-Dokumenten heißt es : "Auf allen Plattformen sind die Kollatierungen mit den Namen default, C und POSIX verfügbar. Je nach Betriebssystemunterstützung sind möglicherweise zusätzliche Kollatierungen verfügbar." Sie können sehen, mit welchen Kollatierungen PostgreSQL denkt, dass sie verfügbar sind select * from pg_collation;.
Mike Sherrill 'Cat Recall'
1
@Matthieu: Dies ist die beste Einführung (und Vorsicht) in das Thema, das ich kenne: Randfälle, die man im Auge behalten sollte. Teil 1 - Text .
Mike Sherrill 'Cat Recall'
1
@Matthieu: Die Unicode-FAQ macht auch Spaß zu lesen. Hier ist, warum es kein eindeutiges Großbuchstaben für gibt. . .
Mike Sherrill 'Cat Recall'
95

Sie können verwenden ILIKE. dh

SELECT id FROM groups where name ILIKE 'administrator'
ADJ
quelle
Es ist korrekt und funktioniert gut für mich. Ich verwende MAC OS X (Mountain Lion).
ADJ
5
Dies wird funktionieren, aber mit langsamer Reaktion. Um einen schnellen Zugriff auf Tabellen zu erhalten, die auf den Ergebnissen von Berechnungen basieren, empfehle ich die Verwendung der lowerFunktion. Weitere Details
anzeigen
1
@AfolabiOlaoluwaAkinwumi Grundsätzlich kommt es darauf an, ob Sie nach Ergebnissen suchen, die dem Filtern bekannter Werte entgegenstehen. Im letzteren Fall sollte ein einzelner einheitlicher Fall auf Datenebene beibehalten werden, damit der Gleichstellungsoperator arbeiten kann. [Persönliche Empfehlung ist Großbuchstaben für Typcode-Werte]
Chris Marisic
53

Sie können auch das ILIKESchlüsselwort nachlesen . Es kann manchmal sehr nützlich sein, obwohl es nicht dem SQL-Standard entspricht. Weitere Informationen finden Sie hier: http://www.postgresql.org/docs/9.2/static/functions-matching.html

Priidu Neemre
quelle
9
Hier ist auf böswillige Benutzereingaben zu achten. Wenn Sie eine Abfrage wie ausführen, müssen Sie email ILIKE 'user-input-email-here'die Benutzereingaben umgehen. Andernfalls können Personen Zeichen wie% eingeben, die mit etwas übereinstimmen.
Matt De Leon
2
@ MattDeLeon Hallo. Gut gesagt. Aber ich möchte dich nur fragen, ob ich benutze ILIKEund prepared statementswird mich das schützen sql injection?
Slevin
Ich bin mir nicht sicher, ob Sie eine Escape-Zeichenfolge an die vorbereitete Anweisung senden möchten.
Matt De Leon
1
"Das Schlüsselwort ILIKE kann anstelle von LIKE verwendet werden, um die Übereinstimmung gemäß dem aktiven Gebietsschema unabhängig von Groß- und Kleinschreibung zu machen. Dies ist nicht im SQL-Standard enthalten, sondern eine PostgreSQL-Erweiterung." Funktioniert wie ein Zauber in 9.3
Aleksey Deryagin
1
ILIKE ist langsamer als lower(column_name) like %expression%.
Patryk Imosa
28

Sie können auch reguläre POSIX-Ausdrücke verwenden, z

SELECT id FROM groups where name ~* 'administrator'

SELECT 'asd' ~* 'AsD' kehrt zurück t

James Brown
quelle
1
Ich hatte das gleiche Problem, ich brauchte Suchanfragen ohne Berücksichtigung der Groß- und Kleinschreibung in meiner PostgreSQL-Datenbank. Ich dachte darüber nach, die Benutzereingabezeichenfolge in einen regulären Ausdruck umzuwandeln. Jetzt hat die Verwendung von ~ * anstelle von = oder LIKE perfekt funktioniert! Ich musste keine neuen Indizes, Spalten oder was auch immer erstellen. Sicher, die Regex-Suche ist langsamer als der Vergleich von geraden Bytes, aber ich denke nicht, dass die Auswirkungen auf die Leistung so viel größer wären, als zwei Datensätze verarbeiten zu müssen (einer niedriger oder in Großbuchstaben, nur um zu suchen, und dann das entsprechende Original abzurufen Daten aus dem anderen Satz). Außerdem ist das sauberer!
Cyberknight
1
Gut, aber wie geht man zum Beispiel mit regexp_matches ()?
WKT
Laut postgres docs: Der Operator ~~ entspricht LIKE und ~~ * entspricht ILIKE. Es gibt auch! ~~- und! ~~ * -Operatoren, die NOT LIKE bzw. NOT ILIKE darstellen. Alle diese Operatoren sind PostgreSQL-spezifisch.
Sh4
Ich hatte ein Problem, wenn Klammern im Text enthalten sind, es funktioniert nicht. wie: "Code (LC)"
Oshan Wisumperuma
8

Die Verwendung ~*kann die Leistung mit der Funktionalität von INSTR erheblich verbessern.

SELECT id FROM groups WHERE name ~* 'adm'

Zeilen mit einem Namen zurückgeben, der OR enthält, entspricht 'adm'.

Robin Goh
quelle
1
Hey, Robin, willkommen bei SO. James Browns Antwort schlug diese Lösung bereits vor. Darüber hinaus nutzt Ihre vorgeschlagene Antwort Regex in keiner Weise.
Rafael