Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
992 views
in Technique[技术] by (71.8m points)

postgresql - Find rows where text array contains value similar to input

I'm trying to get rows where a column of type text[] contains a value similar to some user input.

What I've thought and done so far is to use the 'ANY' and 'LIKE' operator like this:

select * from someTable where '%someInput%' LIKE ANY(someColum);

But it doesn't work. The query returns the same values as that this query:

select * from someTable where 'someInput' = ANY(someColum);

I've got good a result using the unnest() function in a subquery but I need to query this in WHERE clause if possible.

Why doesn't the LIKE operator work with the ANY operator and I don't get any errors? I thought that one reason should be that ANY operator is in the right-hand of query, but ...

Is there any solution to this without using unnest() and if it is possible in WHERE clause?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It's also important to understand that ANY is not an operator but an SQL construct that can only be used to the right of an operator. More:

The LIKE operator - or more precisely: expression, that is rewritten with to the ~~ operator in Postgres internally - expects the value to the left and the pattern to the right. There is no COMMUTATOR for this operator (like there is for the simple equality operator =) so Postgres cannot flip operands around.

Your attempt:

select * from someTable where '%someInput%' LIKE ANY(someColum);

has flipped left and right operand so '%someInput%' is the value and elements of the array column someColum are taken to be patterns (which is not what you want).

It would have to be ANY(someColum) LIKE '%someInput%' - except that's not possible with the ANY construct which is only allowed to the right of an operator. You are hitting a road block here.

Related:

You can normalize your relational design and save elements of the array in separate rows in a separate table. Barring that, unnest() is the solution, as you already found yourself. But while you are only interested in the existence of at least one matching element, an EXISTS subquery will be most efficient while avoiding duplicates in the result - Postgres can stop the search as soon as the first match is found:

SELECT *
FROM   tbl
WHERE  EXISTS (
    SELECT -- can be empty 
    FROM   unnest(someColum) elem
    WHERE  elem LIKE '%someInput%'
  );

You may want to escape special character in someInput. See:

Careful with the negation (NOT LIKE ALL (...)) when NULL can be involved:


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...