За последние 24 часа нас посетили 20375 программистов и 1198 роботов. Сейчас ищут 658 программистов ...

[РЕШЕНО] Задачка про выбор случайного из группы

Тема в разделе "MySQL", создана пользователем artoodetoo, 5 мар 2019.

  1. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Навеяло вот этой темой: https://php.ru/forum/threads/gruppirovka-znachenij.75370/ но топикстартер как-то сложно и неоднозначно, на мой взгляд, сформулировал задачу. Поэтому сделаю свой вариант.

    Пусть есть таблица с полем, где значения повторяются. Например дети и их возраст.
    Маша, 3
    Петя, 3
    Саша, 5
    Кузьма, 5
    Фархат, 4
    Зина, 7
    Зидан, 3
    Родриго, 4​

    Надо создать выборку детей, где каждого возраста будет по одному ребенку. Причем если в возрастной группе более одного ребенка, то выбираем случайного из этой группы.
    Случайный — значит результат может меняться при повторном вызове запроса.

    Использовать диалект MySQL и строгость в группировке.

    Я знаю, что @Valick знает возможное решение. Наверное есть и другие варианты.
    --- Добавлено ---
    Варианты валидных выборок:
    Маша, 3
    Фархат, 4
    Саша, 5
    Зина, 7​
    и
    Петя, 3
    Фархат, 4
    Кузьма, 5
    Зина, 7​
    и т.д.

    Update:
    Добавил песочницу с неправильным запросом, который многим приходит на ум:
    https://www.db-fiddle.com/f/msQEzeuaYXJ42qTfKnkReb/0
    предлагайте правильный, но пожалуйста сразу не спойлерите, можно в личку
     
  2. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.155
    Симпатии:
    1.769
    Адрес:
    :сердА
    А как же сэндбокс на мускульфиддле предоставить? На все вопросы про лень ответ положительный.
     
  3. Valick

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

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    @Fell-x27, желательно не выкладывать ответы в теме в течение некоторого времени, достаточно отписаться, что задача решена и отправить решение в личку @artoodetoo
     
    artoodetoo нравится это.
  4. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    А в чем проблема то? В том что бы сделать поведение GROUP BY как раньше?
     
  5. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Никаких проблем :)

    P.S. По просьбам общественности добавил фиддл.
     
    #5 artoodetoo, 5 мар 2019
    Последнее редактирование: 5 мар 2019
  6. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    @runcore показал рабочий запрос
     
  7. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    @keren - зачёт

    Есть уже три разных решения. Завтра утром выложу, пока принимаются ещё :)
     
  8. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Результаты (обновлено со вторым вариантом от runcore):

    @Valick - https://www.db-fiddle.com/f/g4LM5uEP1Z8kabtmHidr8x/0

    Код (Text):
    1.  
    2. SELECT
    3.    SUBSTRING_INDEX(
    4.       GROUP_CONCAT(`child_name`
    5.           ORDER BY RAND()
    6.           SEPARATOR '%%%'),
    7.     '%%%',1) `name`,
    8.     `child_age`
    9.   FROM `children`
    10.   GROUP BY `child_age`
    - - - - -


    @runcore - https://www.db-fiddle.com/f/xyWVxAR7vDtxoiH83Y4u2R/0

    Код (Text):
    1.  
    2. SELECT
    3.   (SELECT child_name FROM children WHERE child_age=c.child_age ORDER BY RAND() LIMIT 1)  AS name
    4.   ,c.child_age AS age
    5. FROM children c
    6. GROUP BY c.child_age
    - - - - -


    @runcore #2 - https://www.db-fiddle.com/f/kfr8EvNiksHeQKxbBkTNeP/1
    Код (Text):
    1.  
    2. SELECT c.child_age, c.child_name, @age:=child_age
    3. FROM ( SELECT * FROM children ORDER BY child_age, RAND() ) c
    4.     ,(SELECT @age:=0) cc
    5. WHERE c.child_age != @age
    - - - - -


    @keren - https://www.db-fiddle.com/f/skFkugv5GJkQeYqkVdTVBS/0

    Код (Text):
    1.  
    2. select name, age from
    3. (select child_age as age,
    4. (select child_name from children where child_age=age
    5. order by rand() limit 1) as name from children
    6. group by child_age) as t
    - - - - -


    Все эти запросы рабочие. По сути здесь три, а не четыре приёма:
    1. трюк с сортировкой внутри group_concat();
    2. подзапрос с лимитом в одну строку внутри фразы select;
    3. переменная mysql помогает обнаружить смену возраста в отсортированном списке.
    Лично мне больше нравится с group_concat.

    От себя:
    Чтобы масштабировать приемы (1) и (2) на бОльшее число колонок (например если надо ещё фамилию и адрес вывести), нужно в случайной части находить ID а не имя, и использовать его в новом джойне с той же таблицей children: click here.
    Приём (3) изначально готов к любому числу колонок.

    (Наверное @keren пробовал расширенный запрос - больше двух колонок - иначе я не понимаю зачем здесь лишний уровень подзапросов.)

    @runcore в личке упоминал и вариант с group_concat, правда в незавершённом виде. То есть он просчитал всё :)

    Все молодцы, спасибо! Уверен, эту тему будут нагугливать и на неё ссылаться.
     
    #8 artoodetoo, 6 мар 2019
    Последнее редактирование: 6 мар 2019
    Deonis нравится это.
  9. Chushkin

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

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
  10. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    А почему ты решил не использовать готовую песочницу, а придумать свои имена? Я попробовал приспособить с мобилы, но очень неудобно - бросил.
     
  11. Chushkin

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

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    1) Работаешь на мобильнике? Круто. Я до такого не дорос пока. :)
    2) Я не использую всякие "песочницы", гитхабы и т.п. - у меня своя среда разработки на своём рабочем компе. Там делаю, там тестирую.
    А если нужно именно положить в "песочницу", нууу переформатируй да положи, делов то на пять минут.
     
  12. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Когда я работаю, я на форум не хожу :)
    --- Добавлено ---
    Спасибо, может быть как-нибудь, если не забуду.
     
  13. Valick

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

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    нашёл чем гордится...
     
  14. Chushkin

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

    С нами с:
    17 дек 2010
    Сообщения:
    1.062
    Симпатии:
    91
    Адрес:
    Мещёра, Центр, Болото N3
    Угу, есть чем.
    А когда начну гордиться, что использую "песочницы", уйду из разрабов, ибо "сдох разраб, остался пшик". :(
    п.с. Извиняюсь за трёп не по делу...