MySQL Множественный СЛУЧАЙ, КОГДА в предложении WHERE не работает

#mysql #sql #string #where-clause #sql-like

#mysql #sql #строка #where-предложение #sql-подобный

Вопрос:

Я пытаюсь оптимизировать поисковую систему моего веб-сайта. Моя база данных содержит фразы. @word определяется как varchar и содержит фразу, аналогичную той, которая существует в БД. Я хочу, чтобы, если данная поисковая фраза точно соответствует записи в БД, запись будет выбрана, если ничего не удалось найти, выполните поиск с like '%phrase%' помощью, и если с помощью этого метода ничего не будет найдено, тогда MATCH columnx against (phrase) следует использовать метод. Это код, который я пробовал с:

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

Чтобы убедиться, что обращения в отдельном запросе select работают нормально, я использовал их отдельно в предложении where. Я получаю результат для этих запросов:

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

и

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

И, как и ожидалось, никакого результата для:

 select distinct columnx from view_materialisiert where columnx like @word;
 

Вопрос в том, почему я вообще не получаю никакого результата, когда использую условие case?

Комментарии:

1. что я делаю не так? Ничего. За исключением написания избыточного кода. И нет результата для: Введите значение, для @word которого строго равно columnx в некоторой строке.

2. Когда я ввожу точное значение, доступное в базе данных, я получаю результаты, но смысл предложения case заключается в том, что если первый случай не сработал, то второй случай. Итак, если я ввожу значение для @word, которое не совсем совпадает с значением в DB, я ожидаю, что либо во втором, либо в другом случае они будут найдены, но почему я не получаю никаких результатов с этим предложением where?

3. Потому что значение, отсутствующее в столбце, дает FALSE, когда вы используете LIKE . И это FALSE — не равно null. Таким образом, 2-е условие НЕ проверяется.

4. Понял, спасибо. Я думал, что это похоже на объединение таблиц, где, если значение не существует, приведет к нулю. Таким образом, решение состоит в том, чтобы заменить «не является нулевым» на «является истинным». Вы можете ответить на вопрос правильным запросом и пояснением, что условия проверяются с помощью TRUE и FALSE, если хотите.

Ответ №1:

Если вы хотите, чтобы значения совпадали с любым из трех условий, вы можете использовать логическую логику:

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

Или вы можете расширить case логику:

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

Однако я не уверен, что это действительно то, чего вы ожидаете. Похоже, вы хотите итеративно проверять условия, пробуя следующее только тогда, когда предыдущее не соответствовало всей таблице. Этот тип логики обычно реализуется с union all помощью и 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, '%'))
 

То, как база данных оптимизирует такой запрос, сильно зависит от ваших данных и других факторов. В лучшем случае следующие члены будут «пропущены», как только один член вернет что-либо (потому что в not exists подзапросе это совершенно четко указано), но гарантии нет. Вам нужно будет оценить производительность вашего фактического набора данных.

Ответ №2:

Делать только

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

Это очень быстро. Это выражение устраняет необходимость в точном совпадении и некоторых других случаях.

Упомянутые OR подходы довольно неэффективны. Они будут проверять каждую строку, обычно с каждым тестом.

Предостережения:

  • «Короткие» слова не могут быть использованы.
  • Слова «Стоп» не могут быть использованы.
  • Если вы не будете осторожны с этими ограничениями, вы не получите ничего или все. Итак, сделайте некоторую предварительную обработку, чтобы решить, когда MATCH будет работать.