#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
будет работать.