261

I have a simple list of ~25 words. I have a varchar field in PostgreSQL, let's say that list is ['foo', 'bar', 'baz']. I want to find any row in my table that has any of those words. This will work, but I'd like something more elegant.

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

5 Answers 5

414

PostgreSQL also supports full POSIX regular expressions:

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

The ~* is for a case insensitive match, ~ is case sensitive.

Another option is to use ANY:

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

You can use ANY with any operator that yields a boolean. I suspect that the regex options would be quicker but ANY is a useful tool to have in your toolbox.

Sign up to request clarification or add additional context in comments.

2 Comments

Interestingly, while both of these methods are more elegant than @chmullig 's solution (so +1), when checking 3 options at least, they execute significantly slower on large tables (91.5 million records in my case). I was seeing a time increase of about 2x when using either of these. Any idea why that might be?
@sage88 I don't know off the top of my head but Erwin Brandstetter might and adding trigram indexes might help.
235

You can use Postgres' SIMILAR TO operator which supports alternations, i.e.

select * from table where lower(value) similar to '%(foo|bar|baz)%'; 

5 Comments

Regex might speed this up a bit: dba.stackexchange.com/questions/10694/…
How do you know it ? most of documentation I've read says that regex are slower and a LIKE %...
According to dba.stackexchange.com/a/10696/27757 SIMILAR TO is internally translated to a regex search
I think using lower() is ineffective because it will first convert each string to lowercase, which is more costly than only a case-insensitive match
if you are using jpa then same native query can be written as below @Query(value = "select * from table_name where lower(< filter col name >) similar to lower(CONCAT('%', :string, '%')) ", nativeQuery = true) List<Object[]> test2(@Param("string") String string); Here string = (foo|bar|baz)
30

Actually there is an operator for that in PostgreSQL:

SELECT * FROM table WHERE lower(value) ~~ ANY('{%foo%,%bar%,%baz%}'); 

3 Comments

So can ilike be used with any & array in the same way? This looks clean if there is no need for fancy regex. Or is it going to be translated to regex internally anyway?
@mlt That is a good question, reading the doc does not provide explicit answer. SIMILAR TO does convert into Regular Expression, ~ operator stands for POSIX Regular Expression, but this is not clear for LIKE.
0

One 'elegant' solution would be to use full text search: http://www.postgresql.org/docs/9.0/interactive/textsearch.html. Then you would use full text search queries.

1 Comment

Downvote, because this is only a link that would be better suited as a comment.
0

All currently supported versions (9.5 and up) allow pattern matching in addition to LIKE.

Reference: https://www.postgresql.org/docs/current/functions-matching.html

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.