Curinga do PostgreSQL COMO para uma lista de palavras

156

Eu tenho uma lista simples de ~ 25 palavras. Eu tenho um campo varchar no PostgreSQL, digamos que a lista seja ['foo', 'bar', 'baz']. Quero encontrar qualquer linha na minha tabela que contenha alguma dessas palavras. Isso vai funcionar, mas eu gostaria de algo mais elegante.

select *
from table
where (lower(value) like '%foo%' or lower(value) like '%bar%' or lower(value) like '%baz%')
chmullig
fonte

Respostas:

166

Você pode usar o SIMILAR TOoperador do Postgres que suporta alternações, ou seja,

select * from table where lower(value) similar to '%(foo|bar|baz)%';
Mainframe nórdico
fonte
1
O Regex pode acelerar um pouco isso: dba.stackexchange.com/questions/10694/…
approxiblue
Como você sabe ? a maior parte da documentação que li diz que o regex é mais lento e
semelhante a
5
De acordo com dba.stackexchange.com/a/10696/27757, SIMILAR TO é traduzido internamente para uma pesquisa regex
Mark K Cowan
Acho que usando lower()é ineficaz porque ele vai primeiro converter cada cadeia para minúsculas, que é mais caro do que apenas uma combinação case-insensitive
gilad Mayani
229

O PostgreSQL também suporta expressões regulares completas do POSIX :

select * from table where value ~* 'foo|bar|baz';

O ~*é para uma correspondência que não diferencia maiúsculas de minúsculas, diferencia ~maiúsculas de minúsculas.

Outra opção é usar QUALQUER :

select * from table where value  like any (array['%foo%', '%bar%', '%baz%']);
select * from table where value ilike any (array['%foo%', '%bar%', '%baz%']);

Você pode usar QUALQUER com qualquer operador que produz um booleano. Eu suspeito que as opções de regex seriam mais rápidas, mas QUALQUER é uma ferramenta útil para ter em sua caixa de ferramentas.

mu é muito curto
fonte
Curiosamente, embora esses dois métodos sejam mais elegantes que a solução do @chmullig (portanto +1), ao marcar três opções pelo menos, eles são executados significativamente mais lentamente em tabelas grandes (91,5 milhões de registros no meu caso). Eu estava vendo um aumento de tempo de cerca de 2x ao usar um desses. Alguma idéia do porquê disso?
precisa saber é
@ sage88 Não sei de nada, mas Erwin Brandstetter pode e adicionar índices de trigramas pode ajudar.
mu é muito curto
13

Na verdade, existe um operador para isso no PostgreSQL:

SELECT *
FROM table
WHERE lower(value) ~~ ANY('{%foo%,%bar%,%baz%}');
jlandercy
fonte
Assim, o ilike pode ser usado com qualquer & array da mesma maneira? Parece limpo se não houver necessidade de regex sofisticado. Ou será traduzido para regex internamente?
mlt
@ mlt Essa é uma boa pergunta, a leitura do documento não fornece uma resposta explícita. SIMILAR TOconverter em Expressão regular, o ~operador significa Expressão regular POSIX, mas isso não está claro LIKE.
jlandercy
0

Uma solução 'elegante' seria usar a pesquisa de texto completo: http://www.postgresql.org/docs/9.0/interactive/textsearch.html . Então você usaria consultas de pesquisa de texto completo.

Kalendae
fonte
1
Votos negativos, porque este é apenas um link que seria mais adequado como comentário.
toraritte