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%')

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)%';

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.


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%}');


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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.