Amir
Amir

Reputation: 441

MySQL Multiple CASE WHEN in WHERE clause not working

I am trying to optimize the search engine of my wensite. My data base contains phrases. @word is defined as varchar and contains a similar phrase to the one which exist in the DB. I want if the given search phrase matches exactly to the entry in DB the entry will be chosen, if nothing could be found, search with like '%phrase%' and if nothing will be find with this method, then the MATCH columnx against (phrase) method should be used. This is the code I tried with:

select distinct columnx 
  from tabley 
  where   
      ( CASE when columnx LIKE @word is not null 
             then columnx LIKE @word
             when columnx like concat('%',@word,'%') is not null
             then columnx like concat('%',@word,'%')
             else  MATCH (columnx) AGAINST (@word) END
      );    

To make sure if the cases on a standalone select query works fine I used them separately in where clause. I get result for these queries:

select distinct columnx from view_materialisiert where MATCH (columnx) AGAINST (@word);

and

select distinct columnx from view_materialisiert where columnx like concat('%',@word,'%');

And as expected no result for:

select distinct columnx from view_materialisiert where columnx like @word;

The question is why i dont get any result when I use the case condition at all?

Upvotes: 0

Views: 80

Answers (2)

Rick James
Rick James

Reputation: 142278

Do only

MATCH (columnx) AGAINST ("+word" IN BOOLEAN MODE)

It is very fast. That expression eliminates the need for the exact match and some of the other cases.

The OR approaches mentioned are quite inefficient. They will check every row, usually with every test.

Caveats:

  • "Short" words cannot be used.
  • "Stop" words cannot be used.
  • If you aren't careful about those limitations, you will get nothing or everything. So do some preprocessing to decide when MATCH will work.

Upvotes: 0

GMB
GMB

Reputation: 222432

If you want values that match on any of the three condition, you can use boolean logic:

select columnx
from tabley
where columnx = @word
   or columnx like concat('%', @word, '%')
   or match(columnx) against (@word)

Or you can extend the case logic:

where case
    when columnx = @word                      then 1
    when columnx like concat('%', @word, '%') then 1
    when match(columnx) against (@word)       then 1
end

However I am unsure that's really what you expect. It seems like you want to iteratively check the conditions, trying the next one only when the preceding had no match on the entire table. This type of logic would be typically implemented with union all and not exists:

select columnx
from tabley
where columnx = @word
union all
select columnx
from tabley 
where columnx like concat('%', @word, '%')
    and not exists (select 1 from tabley where columnx = @word)
union all
select columnx
from tabley
where match(columnx) against (@word)
    and not exists (select 1 from tabley where columnx = @word)
    and not exists (select 1 from tabley where columnx like concat('%', @word, '%'))

How the database will optimize such query is highly dependent on your data and other factors. In the best case scenario, the following members will be "skipped" as soon as one member returns anything (because the not exists subquery is quite explicit about that), but there is no guarantee. You would need to assess the performance on your actual dataset.

Upvotes: 1

Related Questions