In Microsoft SQL Server ist es möglich, eine "akzentunempfindliche" Kollatierung (für eine Datenbank, Tabelle oder Spalte) anzugeben, was bedeutet, dass dies für eine Abfrage wie möglich möglich ist
SELECT * FROM users WHERE name LIKE 'João'
eine Reihe mit a finden Joao
Namen zu finden.
Ich weiß, dass es möglich ist, Akzente von Zeichenfolgen in PostgreSQL mit der Contrib-Funktion unaccent_string zu entfernen, aber ich frage mich, ob PostgreSQL diese "akzentunempfindlichen" Kollatierungen unterstützt, damit die SELECT
oben genannten funktionieren.
sql
postgresql
localization
indexing
pattern-matching
Daniel Serodio
quelle
quelle
Antworten:
Verwenden Sie dazu das Modul ohne Akzent - das völlig anders ist als das, auf das Sie verlinken.
Einmal pro Datenbank installieren mit:
Wenn Sie eine Fehlermeldung erhalten wie:
Installieren Sie das Contrib-Paket auf Ihrem Datenbankserver, wie in dieser Antwort beschrieben:
Unter anderem bietet es die Funktion, die
unaccent()
Sie für Ihr Beispiel verwenden können (wo diesLIKE
nicht benötigt wird).Index
Um einen Index für diese Art von Abfrage zu verwenden, erstellen Sie einen Index für den Ausdruck . Postgres akzeptiert jedoch nur
IMMUTABLE
Funktionen für Indizes. Wenn eine Funktion für dieselbe Eingabe ein anderes Ergebnis zurückgeben kann, kann der Index stillschweigend unterbrochen werden.unaccent()
nurSTABLE
nichtIMMUTABLE
Leider
unaccent()
ist nurSTABLE
nichtIMMUTABLE
. Laut diesem Thread zu pgsql-Bugs hat dies drei Gründe:search_path
, der sich leicht ändern kann.Einige Tutorials im Web weisen an, nur die Funktionsvolatilität auf zu ändern
IMMUTABLE
. Diese Brute-Force-Methode kann unter bestimmten Bedingungen brechen.Andere schlagen eine einfache
IMMUTABLE
Wrapper-Funktion vor (wie ich es selbst in der Vergangenheit getan habe).Es gibt eine anhaltende Debatte darüber, ob die Variante mit zwei Parametern erstellt werden soll,
IMMUTABLE
die das verwendete Wörterbuch explizit deklarieren. Lesen Sie hier oder hier .Eine andere Alternative wäre dieses Modul mit einer IMMUTABLE-
unaccent()
Funktion von Musicbrainz , die auf Github bereitgestellt wird. Habe es nicht selbst getestet. Ich denke, ich habe eine bessere Idee :Am besten für jetzt
Dieser Ansatz ist effizienter als andere Lösungen und sicherer .
Erstellen Sie eine
IMMUTABLE
SQL-Wrapper-Funktion, die das Zwei-Parameter-Formular mit einer fest verdrahteten schemaqualifizierten Funktion und einem Wörterbuch ausführt.Da das Verschachteln einer nicht unveränderlichen Funktion das Inlining von Funktionen deaktivieren würde, basieren Sie auf einer Kopie der ebenfalls deklarierten (gefälschten) C-Funktion
IMMUTABLE
. Der einzige Zweck besteht darin, im SQL-Funktions-Wrapper verwendet zu werden. Nicht für den alleinigen Gebrauch gedacht.Die Raffinesse ist erforderlich, da das Wörterbuch in der Deklaration der C-Funktion nicht fest verdrahtet werden kann. (Müsste den C-Code selbst hacken.) Die SQL-Wrapper-Funktion erledigt dies und ermöglicht sowohl Inlining- als auch Ausdrucksindizes.
Löschen Sie
PARALLEL SAFE
beide Funktionen für Postgres 9.5 oder älter.public
Dies ist das Schema, in dem Sie die Erweiterung installiert haben (diespublic
ist die Standardeinstellung).Die explizite Typdeklaration (
regdictionary
) schützt vor hypothetischen Angriffen mit überladenen Varianten der Funktion durch böswillige Benutzer.Früher habe ich mich für eine Wrapper - Funktion auf der Grundlage der
STABLE
Funktionunaccent()
mit dem unaccent Modul ausgeliefert. Diese deaktivierte Funktion Inlining . Diese Version wird zehnmal schneller ausgeführt als die einfache Wrapper-Funktion, die ich zuvor hier hatte.Und das war schon doppelt so schnell wie die erste Version, die
SET search_path = public, pg_temp
die Funktion erweitert hat - bis ich herausfand, dass das Wörterbuch auch schemaqualifiziert werden kann. Dennoch (Postgres 12) aus der Dokumentation nicht allzu offensichtlich.Wenn Sie nicht über die erforderlichen Berechtigungen zum Erstellen von C-Funktionen verfügen, kehren Sie zur zweitbesten Implementierung zurück: Ein
IMMUTABLE
Funktionsumbruch um dieSTABLE
unaccent()
vom Modul bereitgestellte Funktion:Schließlich der Ausdrucksindex , um Abfragen schnell zu machen :
Denken Sie daran , nach jeder Änderung der Funktion oder des Wörterbuchs Indizes neu zu erstellen, die diese Funktion betreffen, z. B. ein direktes Upgrade der Hauptversion, bei dem keine Indizes neu erstellt werden. Die letzten Hauptversionen hatten alle Updates für das
unaccent
Modul.Passen Sie Abfragen an den Index an (damit der Abfrageplaner ihn verwendet):
Sie brauchen die Funktion nicht im richtigen Ausdruck. Dort können Sie auch Zeichenfolgen ohne Akzent wie
'Joao'
direkt angeben .Die schnellere Funktion übersetzt nicht in viel schnellere Abfragen unter Verwendung des Ausdrucksindex . Das arbeitet mit vorberechneten Werten und ist schon sehr schnell. Aber Indexpflege und Abfragen, die den Indexvorteil nicht nutzen.
Die Sicherheit für Client-Programme wurde mit Postgres 10.3 / 9.6.8 usw. verschärft. Sie müssen die Funktion und den Wörterbuchnamen für das Schema qualifizieren, wie bei der Verwendung in Indizes gezeigt. Sehen:
Ligaturen
In Postgres 9.5 oder älteren müssen Ligaturen wie 'Œ' oder 'ß' manuell erweitert werden (falls erforderlich), da
unaccent()
immer ein einzelner Buchstabe ersetzt wird:Sie werden dieses Update lieben, um in Postgres 9.6 nicht zu akzentuieren :
Meine kühne Betonung. Jetzt bekommen wir:
Mustervergleich
Kombinieren Sie dies für
LIKE
oderILIKE
mit beliebigen Mustern mit dem Modulpg_trgm
in PostgreSQL 9.1 oder höher. Erstellen Sie einen Trigramm-GIN- (normalerweise vorzuziehen) oder GIST-Ausdrucksindex. Beispiel für GIN:Kann für Abfragen wie verwendet werden:
Die Pflege von GIN- und GIST-Indizes ist teurer als die von Btree:
Es gibt einfachere Lösungen für nur links verankerte Muster. Weitere Informationen zu Mustervergleich und Leistung:
pg_trgm
bietet auch nützliche Operatoren für "Ähnlichkeit" (%
) und "Entfernung" (<->
) .Trigram-Indizes unterstützen auch einfache reguläre Ausdrücke mit
~
et al. und Muster, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wirdILIKE
:quelle
unaccent(name)
?utf8_general_ci
die Antwort auf diese Art von Problemen?Nein, PostgreSQL unterstützt keine Kollatierungen in diesem Sinne
PostgreSQL unterstützt solche Kollatierungen nicht (akzentunempfindlich oder nicht), da kein Vergleich gleich zurückgeben kann, es sei denn, die Dinge sind binär gleich. Dies liegt daran, dass es intern viele Komplexitäten für Dinge wie einen Hash-Index mit sich bringen würde. Aus diesem Grund wirken sich Kollatierungen im engeren Sinne nur auf die Reihenfolge und nicht auf die Gleichheit aus.
Problemumgehungen
Volltextsuchwörterbuch, das Lexeme nicht akzentuiert.
Für FTS können Sie Ihr eigenes Wörterbuch definieren mit
unaccent
:Was Sie dann mit einem Funktionsindex indizieren können,
Sie können es jetzt ganz einfach abfragen
Siehe auch
An sich nicht akzentuiert.
Das
unaccent
Modul kann auch ohne FTS-Integration alleine verwendet werden. Überprüfen Sie dazu Erwins Antwortquelle
Ich bin mir ziemlich sicher, dass PostgreSQL für die Sortierung auf dem zugrunde liegenden Betriebssystem basiert. Es wird unterstützt neue Sortierungen zu schaffen , und Sortierungen Customizing . Ich bin mir jedoch nicht sicher, wie viel Arbeit das für Sie sein könnte. (Könnte ziemlich viel sein.)
quelle