Dans Microsoft SQL Server, il est possible de spécifier un classement «insensible aux accents» (pour une base de données, une table ou une colonne), ce qui signifie qu'il est possible pour une requête comme
SELECT * FROM users WHERE name LIKE 'João'
pour rechercher une ligne avec un Joao
nom.
Je sais qu'il est possible de dépouiller les accents de chaînes dans PostgreSQL en utilisant la unaccent_string fonction contrib, mais je me demande si PostgreSQL prend en charge ces « de insensibles classements accent » de sorte que le SELECT
dessus fonctionnerait.
sql
postgresql
localization
indexing
pattern-matching
Daniel Serodio
la source
la source
Réponses:
Utilisez le module unaccent pour cela - qui est complètement différent de ce à quoi vous créez un lien.
Installer une fois par base de données avec:
Si vous obtenez une erreur comme:
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ù celaLIKE
ne semble pas nécessaire).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()
seulementSTABLE
pasIMMUTABLE
Malheureusement,
unaccent()
c'est seulementSTABLE
nonIMMUTABLE
. Selon ce fil sur pgsql-bugs , cela est dû à trois raisons: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.
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
fonctionunaccent()
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 laSTABLE
unaccent()
fonction fournie par le module:Enfin, l' index d'expression pour accélérer les requêtes :
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):
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:Vous allez adorer cette mise à jour pour unaccent dans Postgres 9.6 :
Je souligne le mien. Maintenant nous obtenons:
Correspondance de motif
Pour
LIKE
ouILIKE
avec des modèles arbitraires, combinez cela avec le modulepg_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:Peut être utilisé pour des requêtes telles que:
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 avecILIKE
:la source
unaccent(name)
?utf8_general_ci
réponse à ce genre de problèmes?Non, PostgreSQL ne prend pas en charge les classements dans ce sens
PostgreSQL ne prend pas en charge les classements comme celui-ci (insensible aux accents ou non) car aucune comparaison ne peut renvoyer égal à moins que les choses soient égales en binaire. En effet, en interne, cela introduirait beaucoup de complexités pour des choses comme un index de hachage. Pour cette raison, les classements dans leur sens le plus strict n'affectent que l'ordre et non l'égalité.
Solutions de contournement
Dictionnaire de recherche en texte intégral qui désaccentue les lexèmes.
Pour FTS, vous pouvez définir votre propre dictionnaire en utilisant
unaccent
,Que vous pouvez ensuite indexer avec un index fonctionnel,
Vous pouvez maintenant l'interroger très simplement
Voir également
Unaccent en soi.
Le
unaccent
module peut également être utilisé seul sans intégration FTS, pour cela, consultez la réponse d'Erwinla source
Je suis à peu près sûr que PostgreSQL s'appuie sur le système d'exploitation sous-jacent pour le classement. Il prend en charge la création de nouveaux classements et la personnalisation des classements . Je ne sais pas trop combien de travail cela pourrait vous apporter. (Cela pourrait être beaucoup.)
la source