WHERE IN с подзапросом НЕ РАБОТАЕТ, как ожидалось

Я пытаюсь получить результат из своей таблицы категорий, используя созданный мной родительский путь. Когда я запускаю запрос WHERE IN с ручными данными, он работает отлично. Когда я динамически пытаюсь выполнить один и тот же запрос с подзапросом, я получил только один результат вместо четырех ожидаемых. Я не понимаю почему, вы можете мне помочь?

http://sqlfiddle.com/#!2/88b68/6

/*Working query*/
SELECT t.id_categorie FROM t 
WHERE t.id_categorie IN (1396,1399,1403,1412)

/*Not working by subquery ??*/
SELECT cat.id_categorie FROM t as cat
WHERE 
cat.id_categorie IN (SELECT REPLACE(t.path,'.',',') FROM t WHERE t.id_categorie = 1412)

Заранее спасибо,

С уважением,


person lwillems    schedule 13.06.2014    source источник
comment
Это потому, что t.path - это varchar столбец, а не INT.   -  person Rahul    schedule 13.06.2014
comment
См. FIND_IN_SET (), хотя такого рода проблемы могут быть признаком плохого дизайна. Тем не менее, материализованные пути - приемлемая стратегия.   -  person Strawberry    schedule 13.06.2014


Ответы (2)


Использование in со списком, разделенным запятыми, не дает желаемого результата. Даже когда вы используете подзапрос. Вы можете попробовать это:

SELECT cat.id_categorie
FROM t cat
WHERE EXISTS (SELECT 1
              FROM t
              WHERE t.id_categorie = 1412 AND
                    find_in_set(cat.id_categorie, REPLACE(t.path, '.', ',')) > 0
             );

Я не уверен, как выглядят ваши данные или даже что этот запрос должен делать (кажется странным, что подзапрос находится в той же таблице, что и внешний запрос). Однако обычно вы хотите хранить вещи в таблицах, а не в списках с разделителями. Видите ли, в SQL есть встроенная структура данных для списков. Это называется столом.

person Gordon Linoff    schedule 13.06.2014

Причина, по которой это не работает, заключается в том, что ваш внутренний SELECT производит одно VARCHAR, разделенное запятыми, а не четыре отдельных целых числа.

В MySQL вы можете использовать find_in_set, например:

SELECT cat.id_categorie FROM t as cat
WHERE find_in_set(cat.id_categorie, (
  SELECT REPLACE(t.path,'.',',')
  FROM t WHERE t.id_categorie = 1412))

Я заменил выражение IN в вашем запросе на вызов find_in_set, оставив все остальное без изменений.

Демо

Однако это решение в корне ошибочно, поскольку оно хранит несколько значений в одном столбце для представления отношения «многие ко многим». Лучшим подходом к реализации этого требования является использование отдельной таблицы, которая соединяет строки таблицы со связанными с ними строками.

person Sergey Kalinichenko    schedule 13.06.2014
comment
Спасибо, я понимаю :-) Я использую это решение для получения Breadcrumb вместо рекурсивного запроса, не могли бы вы объяснить немного больше предлагаемой лучшей практики? - person lwillems; 13.06.2014
comment
@ user3384179 Если я правильно понимаю, чего вы пытаетесь достичь, ознакомьтесь с ответами на этот вопрос, они показывают, как реализовать отношение к себе в MySQL. - person Sergey Kalinichenko; 13.06.2014