Verwenden Sie dazu das Modul ohne Akzent - das völlig anders ist als das, auf das Sie verlinken.
unaccent ist ein Textsuchwörterbuch, das Akzente (diakritische Zeichen) aus Lexemen entfernt.
Einmal pro Datenbank installieren mit:
CREATE EXTENSION unaccent;
Wenn Sie eine Fehlermeldung erhalten wie:
ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
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 dies LIKEnicht benötigt wird).
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Index
Um einen Index für diese Art von Abfrage zu verwenden, erstellen Sie einen Index für den Ausdruck . Postgres akzeptiert jedoch nur IMMUTABLEFunktionen für Indizes. Wenn eine Funktion für dieselbe Eingabe ein anderes Ergebnis zurückgeben kann, kann der Index stillschweigend unterbrochen werden.
unaccent()nur STABLEnichtIMMUTABLE
Leider unaccent()ist nur STABLEnicht IMMUTABLE. Laut diesem Thread zu pgsql-Bugs hat dies drei Gründe:
- Dies hängt vom Verhalten eines Wörterbuchs ab.
- Es besteht keine fest verdrahtete Verbindung zu diesem Wörterbuch.
- Es kommt also auch auf den Strom an
search_path, der sich leicht ändern kann.
Einige Tutorials im Web weisen an, nur die Funktionsvolatilität auf zu ändernIMMUTABLE . Diese Brute-Force-Methode kann unter bestimmten Bedingungen brechen.
Andere schlagen eine einfache IMMUTABLEWrapper-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 IMMUTABLESQL-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.
CREATE OR REPLACE FUNCTION public.immutable_unaccent(regdictionary, text)
RETURNS text LANGUAGE c IMMUTABLE PARALLEL SAFE STRICT AS
'$libdir/unaccent', 'unaccent_dict';
CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT AS
$func$
SELECT public.immutable_unaccent(regdictionary 'public.unaccent', $1)
$func$;
Löschen Sie PARALLEL SAFEbeide Funktionen für Postgres 9.5 oder älter.
publicDies ist das Schema, in dem Sie die Erweiterung installiert haben (dies publicist 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 STABLEFunktion unaccent()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_tempdie 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 IMMUTABLEFunktionsumbruch um die STABLE unaccent()vom Modul bereitgestellte Funktion:
CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text AS
$func$
SELECT public.unaccent('public.unaccent', $1) -- schema-qualify function and dictionary
$func$ LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT;
Schließlich der Ausdrucksindex , um Abfragen schnell zu machen :
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
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 unaccentModul.
Passen Sie Abfragen an den Index an (damit der Abfrageplaner ihn verwendet):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
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:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
Sie werden dieses Update lieben, um in Postgres 9.6 nicht zu akzentuieren :
Erweitern Sie contrib/unaccentdie Standarddatei unaccent.rules, um alle Unicode bekannten Diakritika zu verarbeiten, und erweitern Sie die Ligaturen korrekt (Thomas Munro, Léonard Benedetti).
Meine kühne Betonung. Jetzt bekommen wir:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
Mustervergleich
Kombinieren Sie dies für LIKEoder ILIKEmit beliebigen Mustern mit dem Modul pg_trgmin PostgreSQL 9.1 oder höher. Erstellen Sie einen Trigramm-GIN- (normalerweise vorzuziehen) oder GIST-Ausdrucksindex. Beispiel für GIN:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
Kann für Abfragen wie verwendet werden:
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
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_trgmbietet 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 wird ILIKE: