Utilisez le module unaccent pour cela - qui est complètement différent de ce à quoi vous créez un lien.
unaccent est un dictionnaire de recherche de texte qui supprime les accents (signes diacritiques) des lexèmes.
Installer une fois par base de données avec:
CREATE EXTENSION unaccent;
Si vous obtenez une erreur comme:
ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
Installez le package contrib sur votre serveur de base de données comme indiqué dans cette réponse connexe:
Entre autres choses, il fournit la fonction que unaccent()
vous pouvez utiliser avec votre exemple (là où cela LIKE
ne semble pas nécessaire).
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Indice
Pour utiliser un index pour ce type de requête, créez un index sur l'expression . Cependant , Postgres n'accepte que les IMMUTABLE
fonctions pour les index. Si une fonction peut renvoyer un résultat différent pour la même entrée, l'index peut être interrompu en silence.
unaccent()
seulement STABLE
pasIMMUTABLE
Malheureusement, unaccent()
c'est seulement STABLE
non IMMUTABLE
. Selon ce fil sur pgsql-bugs , cela est dû à trois raisons:
- Cela dépend du comportement d'un dictionnaire.
- Il n'y a pas de connexion câblée à ce dictionnaire.
- Cela dépend donc aussi du courant
search_path
, qui peut changer facilement.
Certains tutoriels sur le Web demandent simplement de modifier la volatilité de la fonction IMMUTABLE
. Cette méthode de force brute peut casser sous certaines conditions.
D'autres suggèrent une simple IMMUTABLE
fonction wrapper (comme je l'ai fait moi-même dans le passé).
Il y a un débat en cours sur l'opportunité de créer la variante avec deux paramètres IMMUTABLE
qui déclarent explicitement le dictionnaire utilisé. Lisez ici ou ici .
Une autre alternative serait ce module avec une fonction IMMUTABLE unaccent()
de Musicbrainz , fournie sur Github. Je ne l'ai pas testé moi-même. Je pense avoir trouvé une meilleure idée :
Meilleur pour le moment
Cette approche est plus efficace que d'autres solutions flottantes et plus sûre .
Créez une IMMUTABLE
fonction wrapper SQL exécutant le formulaire à deux paramètres avec une fonction et un dictionnaire qualifiés de schéma câblés.
Étant donné que l'imbrication d'une fonction non immuable désactiverait l'intégration de fonction, basez-la sur une copie de la fonction C, (fausse) également déclarée IMMUTABLE
. Son seul but est d'être utilisé dans l'encapsuleur de fonctions SQL. Non destiné à être utilisé seul.
La sophistication est nécessaire car il n'y a aucun moyen de câbler le dictionnaire dans la déclaration de la fonction C. (Nécessiterait de pirater le code C lui-même.) La fonction SQL wrapper fait cela et permet à la fois l'insertion de fonctions et les index d'expression.
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$;
Abandonnez les PARALLEL SAFE
deux fonctions pour Postgres 9.5 ou plus.
public
étant le schéma dans lequel vous avez installé l'extension ( public
c'est la valeur par défaut).
La déclaration de type explicite ( regdictionary
) se défend contre les attaques hypothétiques avec des variantes surchargées de la fonction par des utilisateurs malveillants.
Auparavant, je préconisais une fonction wrapper basée sur la STABLE
fonction unaccent()
fournie avec le module unaccent. Cette fonction désactivée en ligne . Cette version s'exécute dix fois plus vite que la simple fonction wrapper que j'avais ici plus tôt.
Et c'était déjà deux fois plus rapide que la première version qui a ajouté SET search_path = public, pg_temp
à la fonction - jusqu'à ce que je découvre que le dictionnaire peut également être qualifié de schéma. Encore (Postgres 12) pas trop évident d'après la documentation.
Si vous n'avez pas les privilèges nécessaires pour créer des fonctions C, vous êtes de retour à la deuxième meilleure implémentation: Un IMMUTABLE
wrapper de fonction autour de la STABLE
unaccent()
fonction fournie par le module:
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;
Enfin, l' index d'expression pour accélérer les requêtes :
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
N'oubliez pas de recréer les index impliquant cette fonction après toute modification de la fonction ou du dictionnaire, comme une mise à niveau majeure sur place qui ne recréerait pas les index. Les versions majeures récentes avaient toutes des mises à jour pour le unaccent
module.
Adaptez les requêtes pour qu'elles correspondent à l'index (afin que le planificateur de requêtes l'utilise):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
Vous n'avez pas besoin de la fonction dans la bonne expression. Là, vous pouvez également fournir des chaînes non accentuées comme 'Joao'
directement.
La fonction plus rapide ne se traduit pas par des requêtes beaucoup plus rapides utilisant l' index d'expression . Cela fonctionne sur des valeurs pré-calculées et est déjà très rapide. Mais la maintenance d'index et les requêtes n'utilisant pas l'avantage d'index.
La sécurité des programmes clients a été renforcée avec Postgres 10.3 / 9.6.8, etc. Vous devez qualifier le schéma de la fonction et du nom du dictionnaire comme démontré lorsqu'ils sont utilisés dans des index. Voir:
Ligatures
Dans Postgres 9.5 ou des ligatures plus anciennes comme 'Œ' ou 'ß' doivent être développées manuellement (si vous en avez besoin), car unaccent()
remplace toujours une seule lettre:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
Vous allez adorer cette mise à jour pour unaccent dans Postgres 9.6 :
Extension contrib/unaccent
du unaccent.rules
fichier standard pour gérer tous les signes diacritiques connus sous Unicode, et développer correctement les ligatures (Thomas Munro, Léonard Benedetti)
Je souligne le mien. Maintenant nous obtenons:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
Correspondance de motif
Pour LIKE
ou ILIKE
avec des modèles arbitraires, combinez cela avec le module pg_trgm
de PostgreSQL 9.1 ou version ultérieure. Créez un trigramme GIN (généralement préférable) ou un index d'expression GIST. Exemple pour GIN:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
Peut être utilisé pour des requêtes telles que:
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
Les index GIN et GIST sont plus chers à maintenir que les simples btree:
Il existe des solutions plus simples pour les motifs uniquement ancrés à gauche. En savoir plus sur la correspondance de modèles et les performances:
pg_trgm
fournit également des opérateurs%
<->
utiles pour «similarité» ( ) et «distance» ( ) .
Les index trigrammes prennent également en charge les expressions régulières simples avec ~
et al. et correspondance de modèle insensible à la casse avec ILIKE
: