У меня 3 таблицы:
действия, инструменты и, поскольку они разделяют: m отношение table Activities_tools.
Пользователи на моем сайте могут выбирать доступные инструменты на фильтре. Теперь я пытаюсь получить все действия, в которых доступны соответствующие инструменты.
Например, если я выбираю инструменты с идентификаторами 1 и 2 как доступные, я должен получать действия, требующие либо никаких инструментов, инструмента 1, инструмента 2, а также действий, требующих и того, и другого. Поэтому мероприятия, требующие применения других инструментов, должны быть исключены.
Мой запрос, который я пробовал до сих пор, выглядит следующим образом:
SELECT activities.*, GROUP_CONCAT(tool) AS tools
FROM activities
LEFT JOIN activities_tools ON activities_tools.activity = activities.id
WHERE ISNULL(tool) OR tool IN (1,2)
GROUP BY activities.id
(1,2) - это список идентификаторов, выбранных пользователем.
Часть ISNULL решает проблему получения действий, которые не имеют инструментов. Моя проблема теперь заключается в том, что, например, инструмент, имеющий инструменты 1 и 2 по мере необходимости, возвращается, когда доступен только один из них.
Как я могу проверить его сразу с несколькими значениями? Я пытался возиться с GROUP_CONCAT + HAVING + FIND_IN_SET и т.д., Но я не могу придумать решение.
Любая помощь приветствуется.
Попробовав еще несколько вещей и рассмотрев вход отсюда, я нашел свое решение :)
SELECT activities.*, GROUP_CONCAT(tool) AS tools
FROM activities
LEFT JOIN activities_tools ON activities_tools.activity = activities.id
GROUP BY activities.id
HAVING ISNULL(tool) OR FIND_IN_SET(1, tools) = 0 OR FIND_IN_SET(2, tools) = 0 etc.
Элементы "OR FIND_IN_SET (1, tools) = 1" являются идентификатором для исключения. Эта часть запроса генерируется динамически в PHP.
РЕДАКТИРОВАТЬ:
Прочитав супер классный трюк здесь:
MySQL find_in_set с несколькими поисковыми строками
Я скорректировал свое решение:
SELECT activities.*, GROUP_CONCAT(tool) AS tools
FROM activities
LEFT JOIN activities_tools ON activities_tools.activity = activities.id
GROUP BY activities.id
HAVING CONCAT(",", toys, ",") NOT REGEXP ",(x|y|z),"
Где x, y и z равны id исключения. Таким образом, запрос намного короче.
Я думаю, вы можете использовать дополнительную проверку NOT IN:
SELECT activities.*, GROUP_CONCAT(tool) AS tools
FROM activities
LEFT JOIN activities_tools ON activities_tools.activity = activities.id
WHERE ISNULL(tool) OR (tool IN (1,2) AND activities.id NOT IN (SELECT activity FROM activities_tools WHERE tool NOT IN (1,2)))
GROUP BY activities.id