Använd oaccentmodulen för det - som är helt annorlunda än det du länkar till.
unaccent är en textsökningsordbok som tar bort accenter (diakritiska tecken) från lexem.
Installera en gång per databas med:
CREATE EXTENSION unaccent;
Om du får ett felmeddelande som:
ERROR: could not open extension control file "/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
Installera bidragspaketet på din databasserver enligt anvisningarna i detta relaterade svar:
- Fel vid skapande av unaccent-tillägg på PostgreSQL
Den tillhandahåller bland annat funktionen unaccent()
du kan använda med ditt exempel (där LIKE
verkar inte behövas).
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Index
För att använda ett index för den typen av fråga, skapa ett index på uttrycket. Men , Postgres accepterar endast IMMUTABLE
funktioner för index. Om en funktion kan returnera ett annat resultat för samma indata, kan indexet gå sönder.
unaccent()
endast STABIL
inte IMMUTABLE
Tyvärr, unaccent()
är bara STABIL
, inte IMMUTABLE
. Enligt denna tråd om pgsql-bugs beror detta på tre skäl:
- Det beror på beteendet hos en ordbok.
- Det finns ingen fast anslutning till denna ordbok.
- Det beror därför också på den aktuella
sökvägen
, som lätt kan ändras.
Vissa tutorials på webben instruerar att bara ändra funktionsvolatiliteten till IMMUTABLE
. Denna brute-force-metod kan gå sönder under vissa förhållanden.
Andra föreslår en enkel IMMUTABLE
omslagsfunktion (som jag gjorde själv tidigare).
Det pågår en diskussion om man ska göra varianten med två parametrar IMMUTABLE
som deklarerar den använda ordboken uttryckligen. Läs här eller här.
Ett annat alternativ skulle vara den här modulen med en IMMUTABLE unaccent()
funktion av Musicbrainz, tillhandahållen på Github. Har inte testat det själv. Jag tror att jag har kommit på en bättre idé :
Bäst för tillfället
Detta tillvägagångssätt är effektivare som andra lösningar som flyter runt och säkrare .
Skapa en IMMUTABLE
SQL-omslagsfunktion som exekverar formuläret med två parametrar med fast schemakvalificerad funktion och ordbok.
Eftersom kapsling av en oföränderlig funktion skulle inaktivera funktionsinläggning, basera den på en kopia av C-funktionen, (falsk) förklarad IMMUTABLE
också. Det är endast syftet är att användas i SQL-funktionsomslaget. Inte avsett att användas på egen hand.
Det sofistikerade behövs eftersom det inte finns något sätt att hårdkoppla ordboken i deklarationen av C-funktionen. (Kräver att hacka själva C-koden.) SQL-omslagsfunktionen gör det och tillåter både funktion inlining och uttrycksindex.
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$;
Släpp PARALLEL SAFE
från båda funktionerna för Postgres 9.5 eller äldre.
offentlig
är schemat där du installerade tillägget (public
är standard).
Den explicita typdeklarationen (regdictionary
) försvarar sig mot hypotetiska attacker med överbelastade varianter av funktionen från illvilliga användare.
Tidigare förespråkade jag en omslagsfunktion baserad på STABLE
funktion unaccent()
levereras med unaccentmodulen. Den avaktiverade funktionen inlining. Den här versionen körs tio gånger snabbare än den enkla omslagsfunktionen jag hade här tidigare.
Och det var redan dubbelt så snabbt som den första versionen som lade till SET search_path =public, pg_temp
till funktionen - tills jag upptäckte att ordboken också kan schemakvalificeras. Fortfarande (Postgres 12) inte alltför tydligt från dokumentationen.
Om om du saknar de nödvändiga privilegierna för att skapa C-funktioner är du tillbaka till den näst bästa implementeringen:En IMMUTABLE
funktionsomslag runt STABLE
unaccent()
funktion som tillhandahålls av modulen:
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;
Slutligen, uttrycksindex för att göra frågor snabbt :
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
Kom ihåg att återskapa index involverar den här funktionen efter någon ändring av funktion eller ordbok, som en större versionsuppgradering på plats som inte skulle återskapa index. De senaste större utgåvorna hade alla uppdateringar för unaccent
modul.
Anpassa frågor så att de matchar indexet (så att frågeplaneraren använder det):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
Du behöver inte funktionen i rätt uttryck. Där kan du också ange strängar utan accent som 'Joao'
direkt.
Den snabbare funktionen översätts inte till mycket snabbare frågor med uttrycksindex . Det fungerar på förberäknade värden och är redan väldigt snabbt. Men index underhåll och frågor som inte använder indexförmånen.
Säkerheten för klientprogram har skärpts med Postgres 10.3 / 9.6.8 etc. Du behöver för att schemakvalificera funktion och ordboksnamn som visas när det används i några index. Se:
- 'textsökningsordbok "oaccent" finns inte'-poster i postgres-loggen, förmodligen under automatisk analys
Ligaturer
I Postgres 9.5 eller äldre ligaturer som 'Œ' eller 'ß' måste utökas manuellt (om du behöver det), eftersom unaccent()
ersätter alltid en singel brev:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
Du kommer att älska den här uppdateringen så att den inte blir tydligare i Postgres 9.6 :
Förläng
contrib/unaccent
s standardunaccent.rules
fil för att hantera alla diakritiker som är kända för Unicode, och expandera ligaturer korrekt (ThomasMunro, Léonard Benedetti)
Djärv betoning min. Nu får vi:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
Mönstermatchning
För GILLA
eller ILIKE
med godtyckliga mönster, kombinera detta med modulen pg_trgm
i PostgreSQL 9.1 eller senare. Skapa ett trigram-GIN (vanligtvis att föredra) eller GIST-uttrycksindex. Exempel på GIN:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
Kan användas för frågor som:
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
GIN- och GIST-index är dyrare att underhålla än vanligt btree:
- Skillnad mellan GiST och GIN-index
Det finns enklare lösningar för just vänsterförankrade mönster. Mer om mönstermatchning och prestanda:
- Mönstermatchning med LIKE, SIMILAR TO eller reguljära uttryck i PostgreSQL
pg_trgm
tillhandahåller också användbara operatorer för "likhet" (%
) och "avstånd" (<-> ).
Trigramindex stöder också enkla reguljära uttryck med ~
et al. och skiftlägesokänslig mönstermatchning med ILIKE
:
- PostgreSQL-accent + skiftlägesokänslig sökning