Use o módulo sem acento para isso - o que é completamente diferente do que você está vinculando.
unaccent é um dicionário de busca de texto que remove acentos (sinais diacríticos) de lexemas.
Instale uma vez por banco de dados com:
CREATE EXTENSION unaccent;
Se você receber um erro como:
ERROR: could not open extension control file "/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
Instale o pacote contrib em seu servidor de banco de dados conforme instruído nesta resposta relacionada:
- Erro ao criar extensão unaccent no PostgreSQL
Entre outras coisas, ele fornece a função
unaccent()
você pode usar com seu exemplo (onde LIKE
parece não ser necessário). SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Índice
Para usar um índice para esse tipo de consulta, crie um índice na expressão. No entanto , Postgres só aceita
IMMUTABLE
funções para índices. Se uma função puder retornar um resultado diferente para a mesma entrada, o índice poderá ser interrompido silenciosamente. unaccent()
apenas STABLE
não IMMUTABLE
Infelizmente,
unaccent()
é apenas STABLE
, não IMMUTABLE
. De acordo com este tópico no pgsql-bugs, isso se deve a três razões:- Depende do comportamento de um dicionário.
- Não há conexão física com este dicionário.
- Portanto, também depende do
search_path
atual , que pode mudar facilmente.
Alguns tutoriais na web instruem apenas alterar a volatilidade da função para
IMMUTABLE
. Este método de força bruta pode quebrar sob certas condições. Outros sugerem um simples
IMMUTABLE
função wrapper (como eu fiz no passado). Há um debate em andamento se deve fazer a variante com dois parâmetros
IMMUTABLE
que declara o dicionário usado explicitamente. Leia aqui ou aqui. Outra alternativa seria este módulo com um IMMUTABLE
unaccent()
função do Musicbrainz, fornecida no Github. Eu mesmo não testei. Acho que tive uma ideia melhor :Melhor por enquanto
Essa abordagem é mais eficiente que outras soluções disponíveis e mais segura .
Crie um
IMMUTABLE
Função wrapper SQL executando o formulário de dois parâmetros com função e dicionário qualificados pelo esquema com fio. Como aninhar uma função não imutável desabilitaria o inlining da função, baseie-a em uma cópia da função C, (falsa) declarada
IMMUTABLE
também. É apenas O objetivo é ser usado no wrapper da função SQL. Não é para ser usado sozinho. A sofisticação é necessária, pois não há como conectar o dicionário na declaração da função C. (Seria necessário hackear o próprio código C.) A função wrapper SQL faz isso e permite a função inlining e índices de expressão.
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$;
Solte
PARALLEL SAFE
de ambas as funções para Postgres 9.5 ou anterior. public
sendo o esquema onde você instalou a extensão (public
é o padrão). A declaração de tipo explícita (
regdictionary
) defende contra ataques hipotéticos com variantes sobrecarregadas da função por usuários mal-intencionados. Anteriormente, defendia uma função wrapper baseada no
STABLE
função unaccent()
enviado com o módulo unaccent. Essa função inlining desativada. Esta versão executa dez vezes mais rápido do que a função wrapper simples que eu tinha aqui antes.E isso já era duas vezes mais rápido que a primeira versão que adicionou
SET search_path = public, pg_temp
para a função - até que descobri que o dicionário também pode ser qualificado pelo esquema. Ainda (Postgres 12) não é muito óbvio na documentação. Se você não tem os privilégios necessários para criar funções C, você está de volta à segunda melhor implementação:Um
IMMUTABLE
wrapper de função em torno do STABLE
unaccent()
função fornecida pelo 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 fim, o índice de expressão para fazer consultas rápidas :
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
Lembre-se de recriar índices envolvendo essa função após qualquer alteração na função ou dicionário, como uma atualização de versão principal no local que não recriaria índices. Os principais lançamentos recentes tiveram atualizações para o
unaccent
módulo. Adapte as consultas para corresponder ao índice (para que o planejador de consultas o use):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
Você não precisa da função na expressão correta. Lá você também pode fornecer strings não acentuadas como
'Joao'
diretamente. A função mais rápida não se traduz em consultas muito mais rápidas usando o índice de expressão . Isso opera em valores pré-calculados e já é muito rápido. Mas a manutenção do índice e as consultas que não usam o benefício do índice.
A segurança para programas clientes foi reforçada com o Postgres 10.3 / 9.6.8 etc. Você precisa para qualificar o esquema e o nome do dicionário conforme demonstrado quando usado em qualquer índice. Ver:
- 'dicionário de pesquisa de texto "unaccent" não existe' entradas no log do postgres, supostamente durante a análise automática
Ligaduras
No Postgres 9.5 ou mais antigo ligaduras como 'Œ' ou 'ß' precisam ser expandidas manualmente (se você precisar), pois
unaccent()
sempre substitui um único carta:SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
Você vai adorar esta atualização para unaccent no Postgres 9.6 :
Estendercontrib/unaccent
padrão dounaccent.rules
para lidar com todos os sinais diacríticos conhecidos do Unicode e expandir as ligaduras corretamente (Thomas Munro, Léonard Benedetti)
Minha ênfase em negrito. Agora obtemos:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
Correspondência de padrões
Para
LIKE
ou ILIKE
com padrões arbitrários, combine isso com o módulo pg_trgm
no PostgreSQL 9.1 ou posterior. Crie um trigrama GIN (normalmente preferível) ou índice de expressão GIST. Exemplo para GIN:CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
Pode ser usado para consultas como:
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
Índices GIN e GIST são mais caros de manter do que btree simples:
- Diferença entre o índice GiST e GIN
Existem soluções mais simples para padrões apenas ancorados à esquerda. Mais sobre correspondência de padrões e desempenho:
- Correspondência de padrões com LIKE, SIMILAR TO ou expressões regulares no PostgreSQL
pg_trgm
também fornece operadores úteis para "semelhança" (%
) e "distância" (<->
). Índices Trigram também suportam expressões regulares simples com
~
et ai. e não diferencia maiúsculas de minúsculas correspondência de padrões com ILIKE
:- Acento PostgreSQL + pesquisa sem distinção entre maiúsculas e minúsculas