Usa il modulo unaccent per quello, che è completamente diverso da quello a cui ti stai collegando.
unaccent è un dizionario di ricerca testuale che rimuove gli accenti (segni diacritici) dai lessemi.
Installa una volta per database con:
CREATE EXTENSION unaccent;
Se ricevi un errore del tipo:
ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
Installa il pacchetto contrib sul tuo server database come indicato in questa risposta correlata:
Tra le altre cose, fornisce la funzione unaccent()
che puoi usare con il tuo esempio (dove LIKE
sembra non necessaria).
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Indice
Per utilizzare un indice per quel tipo di query, crea un indice sull'espressione . Tuttavia , Postgres accetta solo IMMUTABLE
funzioni per gli indici. Se una funzione può restituire un risultato diverso per lo stesso input, l'indice potrebbe interrompersi silenziosamente.
unaccent()
solo STABLE
noIMMUTABLE
Sfortunatamente, unaccent()
è solo STABLE
, non IMMUTABLE
. Secondo questo thread su pgsql-bugs , ciò è dovuto a tre motivi:
- Dipende dal comportamento di un dizionario.
- Non esiste una connessione cablata a questo dizionario.
- Dipende quindi anche dalla corrente
search_path
, che può cambiare facilmente.
Alcuni tutorial sul Web indicano di modificare la volatilità della funzione in IMMUTABLE
. Questo metodo di forza bruta può rompersi in determinate condizioni.
Altri suggeriscono una semplice IMMUTABLE
funzione wrapper (come ho fatto io in passato).
È in corso il dibattito se rendere la variante con due parametri IMMUTABLE
che dichiari esplicitamente il dizionario utilizzato. Leggi qui o qui .
Un'altra alternativa sarebbe questo modulo con un IMMUTABILE unaccent()
funzione Musicbrainz , disponibile su Github. Non l'ho testato da solo. Penso di aver avuto un'idea migliore :
Meglio per ora
Questo approccio è più efficiente poiché altre soluzioni fluttuano e più sicure .
Creare una IMMUTABLE
funzione wrapper SQL che esegua il modulo a due parametri con funzione e dizionario qualificati per schema cablati.
Poiché annidare una funzione non immutabile disabiliterebbe la funzione inlining, basarla su una copia della funzione C, dichiarata IMMUTABLE
anche (fake) . Il suo unico scopo è quello di essere utilizzato nel wrapper della funzione SQL. Non pensato per essere utilizzato da solo.
La sofisticazione è necessaria in quanto non c'è modo di cablare il dizionario nella dichiarazione della funzione C. (Richiederebbe l'hacking del codice C stesso.) La funzione wrapper SQL lo fa e consente sia l'inlining di funzioni che gli indici di espressione.
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$;
Elimina PARALLEL SAFE
da entrambe le funzioni per Postgres 9.5 o versioni precedenti.
public
essendo lo schema in cui hai installato l'estensione ( public
è l'impostazione predefinita).
La dichiarazione di tipo esplicita ( regdictionary
) difende da attacchi ipotetici con varianti sovraccariche della funzione da parte di utenti malintenzionati.
In precedenza, ho sostenuto una funzione wrapper basata sulla STABLE
funzione unaccent()
fornita con il modulo unaccent. Quella funzione disabilitata in linea . Questa versione viene eseguita dieci volte più velocemente della semplice funzione wrapper che avevo qui prima.
E questo era già due volte più veloce della prima versione aggiunta SET search_path = public, pg_temp
alla funzione, finché non ho scoperto che anche il dizionario può essere qualificato come schema. Ancora (Postgres 12) non troppo ovvio dalla documentazione.
Se ti mancano i privilegi necessari per creare funzioni C, sei tornato alla seconda migliore implementazione: Un IMMUTABLE
wrapper di funzione attorno alla STABLE
unaccent()
funzione fornita dal modulo:
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;
Infine, l' indice di espressione per rendere veloci le query :
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
Ricordarsi di ricreare gli indici che coinvolgono questa funzione dopo qualsiasi modifica alla funzione o al dizionario, come un aggiornamento sul posto di una versione principale che non ricrea gli indici. Tutte le versioni principali recenti avevano aggiornamenti per il unaccent
modulo.
Adatta le query in modo che corrispondano all'indice (in modo che venga utilizzato dal pianificatore di query):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
Non hai bisogno della funzione nell'espressione giusta. Lì puoi anche fornire stringhe non accentate come 'Joao'
direttamente.
La funzione più veloce non si traduce in query molto più veloci utilizzando l' indice di espressione . Funziona su valori precalcolati ed è già molto veloce. Ma la manutenzione dell'indice e le query non utilizzano il vantaggio dell'indice.
La sicurezza per i programmi client è stata rafforzata con Postgres 10.3 / 9.6.8 ecc. È necessario qualificare la funzione e il nome del dizionario come dimostrato quando utilizzati in qualsiasi indice. Vedere:
Legature
In Postgres 9.5 o versioni precedenti, le legature come 'or' o 'ß' devono essere espanse manualmente (se necessario), poiché unaccent()
sostituisce sempre una singola lettera:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
Ti piacerà questo aggiornamento a unaccent in Postgres 9.6 :
Estendi contrib/unaccent
il unaccent.rules
file standard di per gestire tutti i segni diacritici noti a Unicode ed espandi correttamente le legature (Thomas Munro, Léonard Benedetti)
Grassetto mio. Ora otteniamo:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
Corrispondenza del modello
Per LIKE
o ILIKE
con pattern arbitrari, combinalo con il modulo pg_trgm
in PostgreSQL 9.1 o successivo. Crea un trigramma GIN (in genere preferibile) o un indice di espressione GIST. Esempio per GIN:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
Può essere utilizzato per query come:
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
Gli indici GIN e GIST sono più costosi da mantenere rispetto al semplice btree:
Esistono soluzioni più semplici per i modelli ancorati a sinistra. Ulteriori informazioni sulla corrispondenza dei modelli e sulle prestazioni:
pg_trgm
fornisce anche utili operatori per "similarità" ( %
) e "distanza" ( <->
) .
Gli indici Trigram supportano anche semplici espressioni regolari con ~
et al. e pattern senza distinzione tra maiuscole e minuscole che corrispondono a ILIKE
: