Подтвердить что ты не робот

Использование MATCH с OR возвращает результаты, которые не удовлетворяют ни одному из условий

Используя MySQL 5.6, этот запрос

SELECT foo
FROM bar
WHERE groupId = '1'
  AND MATCH (foo) AGAINST ('"myQuery"' IN BOOLEAN MODE);

и

SELECT foo
FROM bar
WHERE groupId = '1'
  AND foo like '%myQuery%';

возвращает оба правильных результата, но когда я объединяю их с:

SELECT foo
FROM bar
WHERE groupId = '1'
  AND (
    MATCH (foo) AGAINST ('"myQuery"' IN BOOLEAN MODE)
    OR foo LIKE '%myQuery%'
  );

Я получил несколько дополнительных результатов, которые не появляются ни в одном из первых двух запросов, и не содержат myQuery вообще.

Есть ли какая-нибудь хитрость с круглыми скобками, которые я пропустил?
Или это может быть связано с каким-либо видом кэша индекса? Иногда результаты верны, а вдруг их уже нет.

Я тоже пробовал с

WHERE (
  groupId = '1' AND MATCH (foo) AGAINST ('"myQuery"' IN BOOLEAN MODE)
) OR (
  groupId = '1' AND foo like '%myQuery%'
);

Изменить: вот результаты моих запросов с myQuery = 'gold'.

1 и 2 возвращаются:

"Необычное золото"
"Хорошее золото"
"Супер хорошее золото"
"Гадкое золото"

Последний возвращает:

"Карнизы алмазные"
'Custom'
"Необычное золото"
"Хорошее золото"
"Супер хорошее золото"
"Гадкое золото"

Еще одна вещь, которую я заметил, я запустил Optimize table bar, и тогда результаты верны. Я снова запустил 1-й запрос, а затем 3-й результат больше не верен. Поэтому я действительно подозреваю, что что-то связано с полнотекстовым индексом.

Изменить 2: вот dbFiddle: https://www.db-fiddle.com/f/iSXdTK7EzfoQ46RgDX7wF3/1

4b9b3361

Ответ 1

Самостоятельное объединение, кажется, решает проблему, заставляя БД думать, что это не одно и то же имя столбца в двух предикатах:

SELECT 
   t1.name 
FROM
    m as t1
    INNER JOIN m as t2 ON t1.id = t2.id 
WHERE
    t1.sId = 'N'
    AND (
      MATCH (t1.'name') AGAINST ('"foo"' IN BOOLEAN MODE)
      OR t2.'name' LIKE '%foo%'
    );

Как я уже упоминал в комментарии выше, в исходном SQL-коде кажется, что если MATCH дает ИСТИННЫЙ результат для любой строки, LIKE будет соответствовать чему угодно. Это решает проблему, обрабатывая два столбца имен как разные, даже если они из одной таблицы.

ОБНОВЛЕНИЕ: Интересно, что коррелированный суб-выбор не имеет такого же полезного эффекта:

SELECT 
   t1.name 
FROM
    m as t1
WHERE
    t1.sId = 'N'
    AND (
      MATCH (t1.'name') AGAINST ('"foo"' IN BOOLEAN MODE)
      OR 1 = (SELECT 1 
              FROM m as t2 
              WHERE t1.id = t2.id 
              AND t2.'name' LIKE '%foo%' ) 
    );

Ответ 2

У меня очень сильное ощущение, что вы описали то, что вы хотели бы, чтобы запросы выглядели, но вы фактически используете код для составления запросов, и в вашем коде есть ошибка, которая делает myQuery нулевым.. затем вы сравниваете с '%%', который всегда совпадает.

Когда вы вызываете ошибку, вы должны публиковать фактические запросы, а не какую-то желаемую интерпретацию того, как могут выглядеть запросы, когда они транскрибируются, чтобы действительно соответствовать цели.

Возможно, вы используете заполнители ? ? и забыли установить второе значение, равное 1, при привязке данных?

Ответ 3

Это, кажется, дает желаемый результат

SELECT 
   name
FROM
    m
WHERE
    sId = 'N'
    AND MATCH ('name') AGAINST ('"foo"' IN BOOLEAN MODE)
    OR 'name' LIKE '%foo%';