En Microsoft SQL Server, es posible especificar una intercalación "insensible al acento" (para una base de datos, tabla o columna), lo que significa que es posible para una consulta como
SELECT * FROM users WHERE name LIKE 'João'
para encontrar una fila con un Joao
nombre.
Sé que es posible quitar los acentos de las cadenas en PostgreSQL usando la función contrib unaccent_string , pero me pregunto si PostgreSQL admite estas intercalaciones "insensibles al acento" para que lo SELECT
anterior funcione.
sql
postgresql
localization
indexing
pattern-matching
Daniel Serodio
fuente
fuente
Respuestas:
Use el módulo de unccent para eso, que es completamente diferente de lo que está vinculando.
Instale una vez por base de datos con:
Si recibe un error como:
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 (dondeLIKE
parece que no es necesaria).Í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 queSTABLE
noIMMUTABLE
Desafortunadamente,
unaccent()
es soloSTABLE
, noIMMUTABLE
. Según este hilo sobre pgsql-bugs , esto se debe a tres razones: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 simple
IMMUTABLE
(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.
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ónunaccent()
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 laSTABLE
unaccent()
función proporcionada por el módulo:Por último, el índice de expresión para realizar consultas rápidas :
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):
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:Le encantará esta actualización a unaccent en Postgres 9.6 :
El énfasis audaz es mío. Ahora obtenemos:
La coincidencia de patrones
Para
LIKE
oILIKE
con patrones arbitrarios, combine esto con el módulopg_trgm
en PostgreSQL 9.1 o posterior. Cree un trigrama GIN (normalmente preferible) o un índice de expresión GIST. Ejemplo de GIN:Se puede utilizar para consultas como:
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 conILIKE
:fuente
unaccent(name)
?utf8_general_ci
la respuesta para este tipo de problemas?No, PostgreSQL no admite intercalaciones en ese sentido
PostgreSQL no admite intercalaciones como esa (insensible al acento o no) porque ninguna comparación puede devolver igual a menos que las cosas sean iguales en binario. Esto se debe a que internamente introduciría muchas complejidades para cosas como un índice hash. Por esta razón, las colaciones en su sentido más estricto solo afectan el orden y no la igualdad.
Soluciones alternativas
Diccionario de búsqueda de texto completo que no utiliza lexemas.
Para FTS, puede definir su propio diccionario usando
unaccent
,Que luego puede indexar con un índice funcional,
Ahora puede consultarlo de manera muy simple
Ver también
Sin acento por sí mismo.
El
unaccent
módulo también se puede usar solo sin integración FTS, para eso, consulte la respuesta de Erwinfuente
Estoy bastante seguro de que PostgreSQL se basa en el sistema operativo subyacente para la intercalación. Que no admite la creación de nuevas colaciones , y la personalización de las intercalaciones . Sin embargo, no estoy seguro de cuánto trabajo podría ser para ti. (Podría ser bastante).
fuente