No Microsoft SQL Server, é possível especificar um agrupamento "insensível ao acento" (para um banco de dados, tabela ou coluna), o que significa que é possível para uma consulta como
SELECT * FROM users WHERE name LIKE 'João'
para encontrar uma linha com um Joao
nome.
Eu sei que é possível remover acentos de strings no PostgreSQL usando a função contrib unaccent_string , mas estou me perguntando se o PostgreSQL suporta esses agrupamentos "insensíveis a acentos" para que o SELECT
acima funcione.
sql
postgresql
localization
indexing
pattern-matching
Daniel Serodio
fonte
fonte
Respostas:
Use o módulo unaccent para isso - que é completamente diferente do que você está vinculando.
Instale uma vez por banco de dados com:
Se você receber um erro como:
Instale o pacote contrib em seu servidor de banco de dados conforme instruído nesta resposta relacionada:
Entre outras coisas, ele fornece a função que
unaccent()
você pode usar com seu exemplo (ondeLIKE
parece não ser necessário).Índice
Para usar um índice para esse tipo de consulta, crie um índice na expressão . No entanto , o Postgres só aceita
IMMUTABLE
funções para índices. Se uma função pode retornar um resultado diferente para a mesma entrada, o índice pode quebrar silenciosamente.unaccent()
sóSTABLE
nãoIMMUTABLE
Infelizmente,
unaccent()
é apenasSTABLE
, nãoIMMUTABLE
. De acordo com este tópico sobre pgsql-bugs , isso se deve a três motivos:search_path
, que pode mudar facilmente.Alguns tutoriais na web instruem apenas a alterar a volatilidade da função para
IMMUTABLE
. Este método de força bruta pode quebrar sob certas condições.Outros sugerem uma função de invólucro simples
IMMUTABLE
(como eu fazia no passado).Há um debate em andamento quanto a fazer a variante com dois parâmetros
IMMUTABLE
que declara explicitamente o dicionário usado. Leia aqui ou aqui .Outra alternativa seria este módulo com uma IMUTÁVEL
unaccent()
função por Musicbrainz , fornecida no Github. Não testei sozinho. Acho que tive uma ideia melhor :Melhor por agora
Essa abordagem é mais eficiente do que outras soluções flutuando e mais segura .
Crie uma
IMMUTABLE
função de wrapper SQL executando a forma de dois parâmetros com a função qualificada pelo esquema conectado e um dicionário.Como aninhar uma função não imutável desabilitaria o inlining de função, baseie-o em uma cópia da função C, (falsa) declarada
IMMUTABLE
também. Seu único propósito é ser usado no wrapper de função SQL. Não deve 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 SQL wrapper faz isso e permite o inlining de função e os índices de expressão.
Remova as
PARALLEL SAFE
duas funções para Postgres 9.5 ou mais antigo.public
sendo o esquema onde você instalou a extensão (public
é o padrão).A declaração de tipo explícita (
regdictionary
) protege contra ataques hipotéticos com variantes sobrecarregadas da função por usuários mal-intencionados.Anteriormente, defendi uma função de invólucro com base na
STABLE
funçãounaccent()
fornecida com o módulo unaccent. Essa função desativada inlining . Esta versão executa dez vezes mais rápido do que a função de invólucro simples que tive aqui anteriormente.E isso já foi duas vezes mais rápido do que a primeira versão adicionada
SET search_path = public, pg_temp
à função - até que descobri que o dicionário também pode ser qualificado pelo esquema. Ainda (Postgres 12) não muito óbvio pela documentação.Se você não tiver os privilégios necessários para criar funções C, estará de volta à segunda melhor implementação: um
IMMUTABLE
wrapper de função em torno daSTABLE
unaccent()
função fornecida pelo módulo:Finalmente, o índice de expressão para tornar as consultas rápidas :
Lembre-se de recriar índices envolvendo esta 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. Todos os lançamentos principais recentes tinham atualizações para o
unaccent
módulo.Adapte as consultas para corresponder ao índice (para que o planejador de consultas as use):
Você não precisa da função na expressão certa. Lá você também pode fornecer strings sem ênfase
'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 não usam o benefício do índice.
A segurança para programas cliente foi reforçada com Postgres 10.3 / 9.6.8 etc. Você precisa qualificar o esquema da função e do nome do dicionário conforme demonstrado quando usado em quaisquer índices. Vejo:
Ligaduras
No Postgres 9.5 ou anteriores, ligaduras como 'Œ' ou 'ß' devem ser expandidas manualmente (se necessário), pois
unaccent()
sempre substitui uma única letra:Você vai adorar esta atualização para unaccent no Postgres 9.6 :
Ênfase em negrito minha. Agora temos:
Correspondência de padrões
Para
LIKE
ouILIKE
com padrões arbitrários, combine isso com o módulopg_trgm
no PostgreSQL 9.1 ou posterior. Crie um trigrama GIN (normalmente preferível) ou índice de expressão GIST. Exemplo para GIN:Pode ser usado para consultas como:
Os índices GIN e GIST são mais caros de manter do que o btree simples:
Existem soluções mais simples para padrões ancorados apenas à esquerda. Mais sobre correspondência de padrões e desempenho:
pg_trgm
também fornece operadores%
<->
úteis para "similaridade" ( ) e "distância" ( ) .Os índices trigramas também suportam expressões regulares simples com
~
et al. e o padrão não diferencia maiúsculas de minúsculas combinando comILIKE
:fonte
unaccent(name)
?utf8_general_ci
a resposta para esse tipo de problema?Não, PostgreSQL não suporta agrupamentos nesse sentido
O PostgreSQL não suporta agrupamentos como esse (insensível a acentos ou não) porque nenhuma comparação pode retornar igual a menos que as coisas sejam binárias iguais. Isso ocorre porque internamente ele introduziria muitas complexidades para coisas como um índice hash. Por essa razão, os agrupamentos em seu sentido mais estrito afetam apenas a ordenação e não a igualdade.
Soluções Alternativas
Dicionário de pesquisa de texto completo que unaccents lexemas.
Para FTS, você pode definir seu próprio dicionário usando
unaccent
,Que você pode indexar com um índice funcional,
Agora você pode consultá-lo de forma muito simples
Veja também
Sem acento por si só.
O
unaccent
módulo também pode ser usado sozinho sem integração FTS, para isso verifique a resposta de Erwinfonte
Tenho certeza de que o PostgreSQL depende do sistema operacional subjacente para o agrupamento. Ele oferece suporte à criação de novos agrupamentos e à personalização de agrupamentos . Não tenho certeza de quanto trabalho isso pode ser para você, no entanto. (Pode ser bastante.)
fonte