За последние 24 часа нас посетили 48399 программистов и 1729 роботов. Сейчас ищет 691 программист ...

Создание запроса при помощи count+having

Тема в разделе "MySQL", создана пользователем masterlelik, 25 апр 2013.

  1. masterlelik

    masterlelik Активный пользователь

    С нами с:
    8 ноя 2008
    Сообщения:
    68
    Симпатии:
    0
    Создаю расширенный поиск с группами параметров:
    Например:
    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

    А вот когда добавился второй блок, то не получается создать запрос. Как можно сделать одним запросом?
     
  2. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.128
    Симпатии:
    1.248
    Адрес:
    там-сям
    в таблице t_child поле user_id не является первичным ключем? что там вообще уникально проиндексировано?
     
  3. masterlelik

    masterlelik Активный пользователь

    С нами с:
    8 ноя 2008
    Сообщения:
    68
    Симпатии:
    0
    Уникального ключа нет, т.к. для одного child могут быть записи:
    user_id | cat_id | value
    1 1 1
    1 1 2
    1 1 3
    1 2 4
     
  4. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.128
    Симпатии:
    1.248
    Адрес:
    там-сям
    ну, отвлекаясь от темы, что-то должно быть уникально.

    помоему вы изобретаете заново EAV.
    непонятно что вы хотели сказать с помощью having. если ищете пользователей у которых определенный атрибут равен определенному значению, выразите это через WHERE. или я чего-то не понял в задаче?

    Добавлено спустя 24 минуты 48 секунд:
    кажется я понял.
    допустим
    Код (Text):
    1. SELECT `user_id`
    2. FROM `t_child`
    3. WHERE `cat_id`=1 AND `value` = 1 /* умеют петь */
    и
    Код (Text):
    1. SELECT `user_id`
    2. FROM `t_child`
    3. WHERE `cat_id`=1 AND `value` = 2 /* умеют рисовать */
    как же нам найти кто умеет петь и рисовать одновременно?
    Код (Text):
    1. SELECT c1.`user_id`
    2. FROM `t_child` AS c1
    3. INNER JOIN `t_child` AS c2 ON c1.`user_id` = c2.`user_id`
    4. WHERE
    5.   (c1.`cat_id`=1 AND c1.`value` = 1) /* умеют петь */ AND
    6.   (c2.`cat_id`=1 AND c2.`value` = 2) /* умеют рисовать */
    коряво, да. потому что модель хранения такая.
    зато понятно и допускает усложнение. хотим найти тех, кто одновременно
    - умеет петь
    - умеет рисовать
    - "возраст 4,5 лет" (это кошмарный способ представления!)
    Код (Text):
    1. SELECT c1.`user_id`
    2. FROM `t_child` AS c1
    3. INNER JOIN `t_child` AS c2 ON c1.`user_id` = c2.`user_id`
    4. INNER JOIN `t_child` AS c3 ON c1.`user_id` = c3.`user_id`
    5. WHERE
    6.   (c1.`cat_id`=1 AND c1.`value` = 1) /* умеют петь */ AND
    7.   (c2.`cat_id`=1 AND c2.`value` = 2) /* умеют рисовать */ AND
    8.   (c3.`cat_id`=2 AND c3.`value` = 1) /* 4,5 лет */
     
  5. masterlelik

    masterlelik Активный пользователь

    С нами с:
    8 ноя 2008
    Сообщения:
    68
    Симпатии:
    0
    Т.е. если продолжить дальше, то при добавлении еще нескольких блоков каких-то характеристик, должно появиться столько же 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. если кто-то предложит более красивое решение, буду рад обсудить.
     
  6. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.128
    Симпатии:
    1.248
    Адрес:
    там-сям
    а когда тебе понадобится сделать что-то через ИЛИ, это будет новый приступ головной боли? когда считаем через distinct, а когда нет...

    нормальное решение -- завести таблицу с полным набором нужных полей разных типов. это будет и быстрее, и удобнее.
     
  7. masterlelik

    masterlelik Активный пользователь

    С нами с:
    8 ноя 2008
    Сообщения:
    68
    Симпатии:
    0
    А если поля динамические, сначала 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')
     
  8. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.128
    Симпатии:
    1.248
    Адрес:
    там-сям
    буду :)
    есть задачи, где хранилище атрибут-значение оправдано, но это точно не поля одной формы и точно типа int на всё-про-всё недостаточно. так что желаю тебе поскорее набить все шишки и сделать правильные выводы.