Caractère générique PostgreSQL LIKE pour l'un des mots d'une liste

156

J'ai une simple liste d'environ 25 mots. J'ai un champ varchar dans PostgreSQL, disons que cette liste est ['foo', 'bar', 'baz']. Je veux trouver n'importe quelle ligne de mon tableau contenant l'un de ces mots. Cela fonctionnera, mais j'aimerais quelque chose de plus élégant.

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

Réponses:

166

Vous pouvez utiliser l' SIMILAR TOopérateur de Postgres qui prend en charge les alternances, c'est-à-dire

select * from table where lower(value) similar to '%(foo|bar|baz)%';
Mainframe nordique
la source
1
Regex pourrait accélérer cela un peu: dba.stackexchange.com/questions/10694/…
environ
Comment tu le sais ? la plupart de la documentation que j'ai lue dit que les regex sont plus lentes et un LIKE% ...
DestyNova
5
Selon dba.stackexchange.com/a/10696/27757 SIMILAR TO est traduit en interne en une recherche regex
Mark K Cowan
Je pense que l'utilisation lower()est inefficace car elle convertira d'abord chaque chaîne en minuscules, ce qui est plus coûteux qu'une seule correspondance insensible à la casse
gilad mayani
229

PostgreSQL prend également en charge les expressions régulières POSIX complètes :

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

L' ~*est pour une correspondance insensible à la casse, ~est sensible à la casse.

Une autre option consiste à utiliser TOUT :

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

Vous pouvez utiliser ANY avec n'importe quel opérateur qui produit un booléen. Je soupçonne que les options regex seraient plus rapides, mais ANY est un outil utile à avoir dans votre boîte à outils.

mu est trop court
la source
Fait intéressant, alors que ces deux méthodes sont plus élégantes que la solution de @chmullig (donc +1), en cochant au moins 3 options, elles s'exécutent nettement plus lentement sur de grandes tables (91,5 millions d'enregistrements dans mon cas). Je voyais une augmentation de temps d'environ 2x lors de l'utilisation de l'un ou l'autre. Une idée pourquoi cela pourrait être?
sage88
@ sage88 Je ne sais pas par-dessus ma tête, mais Erwin Brandstetter pourrait et l'ajout d' index trigrammes pourrait aider.
mu est trop court le
13

En fait, il existe un opérateur pour cela dans PostgreSQL:

SELECT *
FROM table
WHERE lower(value) ~~ ANY('{%foo%,%bar%,%baz%}');
jlandercy
la source
Ilike peut donc être utilisé avec n'importe quel tableau & de la même manière? Cela semble propre s'il n'y a pas besoin de regex sophistiquée. Ou va-t-il être traduit en regex en interne de toute façon?
mlt
@mlt C'est une bonne question, la lecture de la doc ne fournit pas de réponse explicite. SIMILAR TOse transforme en expression régulière, l' ~opérateur signifie expression régulière POSIX, mais ce n'est pas clair pour LIKE.
jlandercy
0

Une solution «élégante» serait d'utiliser la recherche en texte intégral: http://www.postgresql.org/docs/9.0/interactive/textsearch.html . Ensuite, vous utiliseriez des requêtes de recherche en texte intégral.

Kalendae
la source
1
Downvote, car ce n'est qu'un lien qui conviendrait mieux en tant que commentaire.
toraritte