Use el módulo de unccent para eso, que es completamente diferente de lo que está vinculando.
unaccent es un diccionario de búsqueda de texto que elimina los acentos (signos diacríticos) de los lexemas.
Instale una vez por base de datos con:
CREATE EXTENSION unaccent;
Si recibe un error como:
ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
Instale el paquete contrib en su servidor de base de datos como se indica en esta respuesta relacionada:
Entre otras cosas, proporciona la función unaccent()
que puede usar con su ejemplo (donde LIKE
parece que no es necesaria).
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Índice
Para usar un índice para ese tipo de consulta, cree un índice en la expresión . Sin embargo , Postgres solo acepta IMMUTABLE
funciones para índices. Si una función puede devolver un resultado diferente para la misma entrada, el índice podría romperse silenciosamente.
unaccent()
solo que STABLE
noIMMUTABLE
Desafortunadamente, unaccent()
es solo STABLE
, no IMMUTABLE
. Según este hilo sobre pgsql-bugs , esto se debe a tres razones:
- Depende del comportamiento de un diccionario.
- No hay una conexión cableada a este diccionario.
- Por tanto, también depende de la corriente
search_path
, que puede cambiar fácilmente.
Algunos tutoriales en la web indican simplemente modificar la volatilidad de la función IMMUTABLE
. Este método de fuerza bruta puede romperse en determinadas condiciones.
Otros sugieren una función de envoltura simpleIMMUTABLE
(como hice yo mismo en el pasado).
Hay un debate en curso sobre si hacer la variante con dos parámetros IMMUTABLE
que declare explícitamente el diccionario utilizado. Leer aquí o aquí .
Otra alternativa sería este módulo con función INMUTABLE unaccent()
de Musicbrainz , proporcionado en Github. No lo he probado yo mismo. Creo que se me ocurrió una idea mejor :
Mejor por ahora
Este enfoque es más eficiente que otras soluciones flotantes y más seguro .
Cree una IMMUTABLE
función contenedora de SQL ejecutando el formulario de dos parámetros con una función y un diccionario calificados por esquema cableado.
Dado que anidar una función no inmutable deshabilitaría la inserción de funciones, basarlo en una copia de la función C, (falsa) declarada IMMUTABLE
también. Su único propósito es ser utilizado en el contenedor de funciones SQL. No está diseñado para usarse solo.
La sofisticación es necesaria ya que no hay forma de cablear el diccionario en la declaración de la función C. (Requeriría piratear el propio código C). La función de envoltura SQL hace eso y permite tanto la función de inserción como los índices de expresión.
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$;
Elimine PARALLEL SAFE
ambas funciones para Postgres 9.5 o versiones anteriores.
public
siendo el esquema donde instaló la extensión ( public
es el predeterminado).
La declaración de tipo explícita ( regdictionary
) defiende contra ataques hipotéticos con variantes sobrecargadas de la función por parte de usuarios malintencionados.
Anteriormente, abogué por una función de envoltura basada en la STABLE
función unaccent()
enviada con el módulo unaccent. Esa función deshabilitada en línea . Esta versión se ejecuta diez veces más rápido que la simple función de contenedor que tenía aquí antes.
Y eso ya era dos veces más rápido que la primera versión que se agregó SET search_path = public, pg_temp
a la función, hasta que descubrí que el diccionario también puede ser calificado por esquema. Aún así (Postgres 12) no es demasiado obvio por la documentación.
Si no tiene los privilegios necesarios para crear funciones en C, está de vuelta a la segunda mejor implementación: una IMMUTABLE
función que envuelve la STABLE
unaccent()
función proporcionada por el módulo:
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;
Por último, el índice de expresión para realizar consultas rápidas :
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
Recuerde volver a crear índices que incluyan esta función después de cualquier cambio en la función o el diccionario, como una actualización de versión importante en el lugar que no recrearía índices. Todas las versiones principales recientes tenían actualizaciones para el unaccent
módulo.
Adapte las consultas para que coincidan con el índice (para que el planificador de consultas las utilice):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
No necesita la función en la expresión correcta. Allí también puede suministrar cadenas sin acento como 'Joao'
directamente.
La función más rápida no se traduce en consultas mucho más rápidas utilizando el índice de expresión . Eso opera con valores precalculados y ya es muy rápido. Pero el mantenimiento del índice y las consultas no utilizan el beneficio del índice.
La seguridad de los programas cliente se ha reforzado con Postgres 10.3 / 9.6.8, etc. Necesita calificar el esquema de la función y el nombre del diccionario como se demuestra cuando se usa en cualquier índice. Ver:
Ligaduras
En Postgres 9.5 o anteriores, las ligaduras como 'Œ' o 'ß' deben expandirse manualmente (si es necesario), ya que unaccent()
siempre sustituye una sola letra:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
Le encantará esta actualización a unaccent en Postgres 9.6 :
Extienda contrib/unaccent
el unaccent.rules
archivo estándar para manejar todos los diacríticos conocidos por Unicode y expanda las ligaduras correctamente (Thomas Munro, Léonard Benedetti)
El énfasis audaz es mío. Ahora obtenemos:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
La coincidencia de patrones
Para LIKE
o ILIKE
con patrones arbitrarios, combine esto con el módulo pg_trgm
en PostgreSQL 9.1 o posterior. Cree un trigrama GIN (normalmente preferible) o un índice de expresión GIST. Ejemplo de GIN:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
Se puede utilizar para consultas como:
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
Los índices GIN y GIST son más costosos de mantener que los btree simples:
Hay soluciones más simples para patrones anclados a la izquierda. Más sobre la coincidencia de patrones y el rendimiento:
pg_trgm
también proporciona operadores%
<->
útiles para "similitud" ( ) y "distancia" ( ) .
Los índices de trigram también admiten expresiones regulares simples con ~
et al. y coincidencia de patrones sin distinción entre mayúsculas y minúsculas con ILIKE
: