Александр Попов: В принципе, можно написать пачку вложенных REPLACE, удалив цифры и пробелы, затем взять длину строки, в которой должны остаться только запятые, и прибавить единицу.
Не выглядеть такая пачка вложенных вызовов будет жутко.
Артём Каретников: Ну, для варианта ИЛИ я и не писал, только для И с уникальными и неуникальными тэгами. Но таки да, второй вариант я на автомате взял с поиска товаров по параметрам, тут такой не нужен, достаточно слегка COUNT поправить в первом варианте.
Кстати, ни большом количестве пользователей и тэгов надо ещё посмотреть, что будет быстрее - DISTINCT или IN (SELECT), когда в выборке будет раз по 10-20 один и тот же user_id повторяться.
Артём Каретников: Нет. Оно у вас только для варианта ИЛИ. Вы для варианта И сделайте, где у пользователя должны быть все указанные тэги, с учётом возможного их повторения в таблице связи.
Артём Каретников: А вы попробуйте сами и убедитесь, что, во первых, никаких дублей не будет, похоже вы JOIN с UNION перепутали. Во-вторых, попробуйте сами реализовать нужную выборку если в таблице связи (а здесь как раз вариант многие-ко-многим с промежуточной таблицей) пары id-ов не уникальны.
Антонов Денис: Ну, если это MySQL 5.7 и выше, то можно воспользоваться функциями для работы с JSON. В PostgreSQL вроде тоже есть такие. Если нет - то выделять нужную подстроку через SUBSTRING и группировать по ней.
MihailDonskoy: valueStyle.split("(") - разделение из переменной valueStyle по символу "(", на выходе даёт массив подстрок, [1] берёт первый элемент этого массива (zero-based).
Добавлю, тот же workbench с нарисованной в нём схемы базы сам готовит все DDL-команды для её создания. Остаётся только немножко подточить напильником, добавить триггеры, функции и процедуры.
Не выглядеть такая пачка вложенных вызовов будет жутко.