Создаю расширенный поиск с группами параметров: Например: 1) Вид работ (поле cat_id) 1, пение (поле value) 2, рисование (поле value) 3, чтение (поле value) 2) Возраст детей (поле cat_id) 4, 5 лет (поле value) 5, 10 лет (поле value) 6, 12 лет (поле value) есть таблица хранящая для каждой набор параметров user_id | mediumint(8) cat_id | mediumint(8) value | mediumint(8) Задача создать запрос для поиска, который в ХТМЛе состоит из чекбоксов. Когда поиск состоял из одного блока, то находил всех детей, которые умели петь и рисовать запросом select user_id, count(user_id) as cnt from t_child where value in (1, 2) group by user_id having cnt>1 А вот когда добавился второй блок, то не получается создать запрос. Как можно сделать одним запросом?
в таблице t_child поле user_id не является первичным ключем? что там вообще уникально проиндексировано?
Уникального ключа нет, т.к. для одного child могут быть записи: user_id | cat_id | value 1 1 1 1 1 2 1 1 3 1 2 4
ну, отвлекаясь от темы, что-то должно быть уникально. помоему вы изобретаете заново EAV. непонятно что вы хотели сказать с помощью having. если ищете пользователей у которых определенный атрибут равен определенному значению, выразите это через WHERE. или я чего-то не понял в задаче? Добавлено спустя 24 минуты 48 секунд: кажется я понял. допустим Код (Text): SELECT `user_id` FROM `t_child` WHERE `cat_id`=1 AND `value` = 1 /* умеют петь */ и Код (Text): SELECT `user_id` FROM `t_child` WHERE `cat_id`=1 AND `value` = 2 /* умеют рисовать */ как же нам найти кто умеет петь и рисовать одновременно? Код (Text): SELECT c1.`user_id` FROM `t_child` AS c1 INNER JOIN `t_child` AS c2 ON c1.`user_id` = c2.`user_id` WHERE (c1.`cat_id`=1 AND c1.`value` = 1) /* умеют петь */ AND (c2.`cat_id`=1 AND c2.`value` = 2) /* умеют рисовать */ коряво, да. потому что модель хранения такая. зато понятно и допускает усложнение. хотим найти тех, кто одновременно - умеет петь - умеет рисовать - "возраст 4,5 лет" (это кошмарный способ представления!) Код (Text): SELECT c1.`user_id` FROM `t_child` AS c1 INNER JOIN `t_child` AS c2 ON c1.`user_id` = c2.`user_id` INNER JOIN `t_child` AS c3 ON c1.`user_id` = c3.`user_id` WHERE (c1.`cat_id`=1 AND c1.`value` = 1) /* умеют петь */ AND (c2.`cat_id`=1 AND c2.`value` = 2) /* умеют рисовать */ AND (c3.`cat_id`=2 AND c3.`value` = 1) /* 4,5 лет */
Т.е. если продолжить дальше, то при добавлении еще нескольких блоков каких-то характеристик, должно появиться столько же INNER JOIN. Может существует иные варианты запроса, или порекомендуете как поменять структуру таблицы (может добавить еще одну-две)? Добавлено спустя 22 минуты 54 секунды: В общем я правильно двигался и решил вопрос. Сначала не работающий запрос у меня выглядел: select distinct `user_id`, count(`cat_id`) as cnt from `t_child` where (((`cat_id`='2' and `value`='1') or (`cat_id`='2' and `value`='2')) or ((`cat_id`='1' and `value`='4')) ) group by `t1`.`id` having cnt > 1 Но, если мне надо было найти детей 5 лет, которые умеют и петь, и рисовать. То он также находил и 10летних детей, потому что было два true в видах работ И понял, что не хватает distinct в count-е и поставив count(distinct `cat_id`) стало нормально и очень шустро находить. P.S. если кто-то предложит более красивое решение, буду рад обсудить.
а когда тебе понадобится сделать что-то через ИЛИ, это будет новый приступ головной боли? когда считаем через distinct, а когда нет... нормальное решение -- завести таблицу с полным набором нужных полей разных типов. это будет и быстрее, и удобнее.
А если поля динамические, сначала 2 блока, потом еще один потом еще два? Не будешь же каждый раз заводить все новые и новые поля? Добавлено спустя 34 минуты 22 секунды: А вот простое и, наверное, самое правильное решение SELECT DISTINCT `user_id` FROM `t_child` WHERE (`cat_id`='2' AND `value` IN ('1','2')) OR (`cat_id`='1' AND `value`='4')
буду есть задачи, где хранилище атрибут-значение оправдано, но это точно не поля одной формы и точно типа int на всё-про-всё недостаточно. так что желаю тебе поскорее набить все шишки и сделать правильные выводы.