За последние 24 часа нас посетили 18020 программистов и 1650 роботов. Сейчас ищут 1667 программистов ...

Помогите с запросом order by перед group by

Тема в разделе "MySQL", создана пользователем vuler, 24 фев 2017.

  1. vuler

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

    С нами с:
    20 май 2015
    Сообщения:
    13
    Симпатии:
    0
    Не могу сделать order by перед group by.
    Вообще запрос несколько сложнее, там 4 таблицы задействованно, но для примера просто выдрал запрос к одной таблице.
    Например есть табилца в виде сообщений форума(forum_msgs) поля - id,topic_id,date,text
    Нужно сгруппировать поля по topic_id - и чтобы вывело последнее сообщение в нем data и текс.
    По логике нужен запрос типа.

    PHP:
    1. SELECT date, text, topic_id
    2. FROM forum_msgs
    3. GROUP BY topic_id
    4. ORDER BY topic_id,date DESC
    В результате в topic_id - выдает первое сообщение, а не последнее по дате, т.к. группирует перед ордером. Вариант есть

    PHP:
    1. SELECT max(date), text, topic_id
    2. FROM forum_msgs
    3. GROUP BY topic_id
    4. ORDER BY topic_id,date DESC
    Но тогда дату подтянет последнюю, но она не будет соответствовать своему тексу сообщения.

    Вообще в моем случае для нескольких таблиц делаю запросы типа -
    PHP:
    1. SELECT * FROM ( SELECT ........ ORDER BY .... ) p1 GROUP BY p1.dir_id
    но тут тоже ничего не выходит
     
    #1 vuler, 24 фев 2017
    Последнее редактирование модератором: 24 фев 2017
  2. Drema

    Drema Новичок

    С нами с:
    20 фев 2017
    Сообщения:
    117
    Симпатии:
    30
    Вам нужно при создании сообщения в таблице topic вставлять id последнего сообщения в теме. Тогда будет проще.

    Иначе всё становится не очень тривиальным и требует дополнительной нагрузки на сервер, что-то типа:
    PHP:
    1. SELECT t1.topic_id,
    2.   (SELECT fm.text
    3.    FROM forum_msgs fm
    4.    WHERE fm.topic_id = t1.topic_id
    5.    ORDER BY fm.date DESC
    6.    LIMIT 1
    7.   ) as text
    8. FROM
    9.    (SELECT DISTINCT topic_id
    10.      FROM forum_msgs
    11.      ORDER BY date DESC
    12.      LIMIT 10 /*Кол-во топиков на странице*/
    13.     ) t1
     
    #2 Drema, 24 фев 2017
    Последнее редактирование модератором: 24 фев 2017
  3. vuler

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

    С нами с:
    20 май 2015
    Сообщения:
    13
    Симпатии:
    0
    Привет :)
    Тут пока о вставке сообщений речи не идет, просто никак не могу понять почему mysql выдает разные по сортировке таблицы в двух запросах типа.
    PHP:
    1. SELECT date, text, topic_id FROM forum_msgs
    2.                         ORDER BY topic_id,date DESC
    и в запросе типа.
    PHP:
    1. SELECT * FROM (SELECT date, text, topic_id FROM forum_msgs
    2.                         ORDER BY topic_id,date DESC) t1
     
    #3 vuler, 24 фев 2017
    Последнее редактирование модератором: 24 фев 2017
  4. Drema

    Drema Новичок

    С нами с:
    20 фев 2017
    Сообщения:
    117
    Симпатии:
    30
    Сортировка гарантируется только в SELECT в котором указан ORDER.
     
  5. vuler

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

    С нами с:
    20 май 2015
    Сообщения:
    13
    Симпатии:
    0
    Ну просто по логике программа в начале должна сделать этот запрос
    PHP:
    1. SELECT date, text, topic_id FROM forum_msgs
    2. ORDER BY topic_id,date DESC
    Построить отсортированную таблицу и уже ее передать Селекту, что выше уровнем.
    Просто применять GROUP BY уже бессмысленно, т.к. таблица передалась не отсортированной..

    PHP:
    1. SELECT * FROM (SELECT date, text, topic_id FROM forum_msgs
    2. ORDER BY topic_id,date DESC) t1 GROUP BY topic_id
    В интернете только такие примеры и пишут, но не работает и все тут, может какие-то настройки в самом mysql надо поменять. хз :(
     
    #5 vuler, 24 фев 2017
    Последнее редактирование модератором: 24 фев 2017
  6. Drema

    Drema Новичок

    С нами с:
    20 фев 2017
    Сообщения:
    117
    Симпатии:
    30
    Логика может быть совсем другая. Например ORDER BY сортирует только "указатели" на записи и если нет вывода, то за скобками это естественно сбрасывается. Там очень много процессов по оптимизации выполнения и они не укладываются в простую логику, которую вы видите по тексту.
     
  7. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.115
    Симпатии:
    1.244
    Адрес:
    там-сям
    Вы ожидаете того, чего SQL не обязан делать.
    Вообще при группировке во фразе select должны быть только поля из фразы group by плюс агрегированные данные из других полей. То есть sum(), max() и т.п.

    https://php.ru/forum/threads/poisk-dvojnyx-zapisej-v-baze-dannyx.59235/#post-477442

    MySql при некоторых настройках не выдаёт ошибку на запросы как у вас, но это не значит, что они правильные. Это бессмыслица. Непредсказуемый результат. Так как реляционная бд подразумевает работу с неупорядоченными наборами данных, любые наблюдаемые "закономерности" в выдаче неправильных группировок могут быть случайными и могут измениться после обновления движка или после бэкап+рестор.
    --- Добавлено ---

    Кроме айди темы в твоей таблице есть айди сообщения? Мне кажется выход в том, чтобы найти последние то есть max(post_id) и использовать их для добывания text. Запрос с подзапросом.
    --- Добавлено ---
    Но в целях оптимизации, как уже писали, в таблице "темы" заводят ссылки на эти самые последние post_id, чтобы избежать дорогостоящих группировок.

    Оптимизируют то, что чаще выполняется!


    Чтение на форуме работает намного чаще, чем запись. Поэтому оправданно при записи сообщения пойти на некоторую дополнительную работу - update таблицы темы.
     
  8. vuler

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

    С нами с:
    20 май 2015
    Сообщения:
    13
    Симпатии:
    0
    мне тут немного подсказали, но запрос решил делать такого типа. Сразу вытаскивает все дерево форума и все подфорумы, находит в каждом подфоруме последнюю тему и последнее сообщение в этой теме(если есть), а также все количество тем и сообщений в каждом разделе.
    Не знаю как по времени будет это работать, если долго можно сохранять где-нибудь в кэш и каждую минуту обновлять, но с моим мини проектом думаю это будет лишним.

    Код (Text):
    1. SELECT t1.*,
    2.                    t2.title,
    3.                    t2.topic_id,
    4.                    t2.topic_date,
    5.                    t2.topic_user_id,
    6.                    t2.topic_user_name,
    7.                    t2.topic_user_login,
    8.                    t2.topic_user_logo,
    9.                    t2.msg_id,
    10.                    t2.msg_date,
    11.                    t2.msg_user_id,
    12.                    t2.msg_user_name,
    13.                    t2.msg_user_login,
    14.                    t2.msg_user_logo
    15.             FROM(
    16.                 SELECT t1.parent_id,
    17.                        t1.id id,
    18.                        t1.name,
    19.                        t1.description,
    20.                        COUNT(*) msgs,
    21.                        COUNT(distinct title) titles
    22.                    
    23.                 FROM forum_dirs t1
    24.                 LEFT JOIN forum_topics t2 ON t1.id=t2.dir_id
    25.                 LEFT JOIN forum_msgs t3 ON t3.topic_id=t2.id
    26.                 GROUP BY t1.id
    27.                 ORDER BY parent_id,pos
    28.             ) t1 LEFT JOIN (
    29.                 SELECT
    30.                     forum_topics.title,
    31.                     forum_topics.dir_id,
    32.                     forum_topics.id topic_id,
    33.                     forum_topics.date topic_date,
    34.                     forum_topics.user_id topic_user_id,
    35.                     users.logo topic_user_logo,
    36.                     users.name topic_user_name,
    37.                     users.login topic_user_login,
    38.                     t3.*
    39.                 FROM forum_topics LEFT JOIN users ON users.id=forum_topics.user_id
    40.              
    41.                 LEFT JOIN (
    42.                     SELECT
    43.                         forum_msgs.id msg_id,
    44.                         forum_msgs.user_id msg_user_id,
    45.                         forum_msgs.date msg_date,
    46.                         forum_msgs.topic_id msg_topic_id,
    47.                         users.logo msg_user_logo,
    48.                         users.name msg_user_name,
    49.                         users.login msg_user_login
    50.                     FROM forum_msgs
    51.                     LEFT JOIN users ON users.id=forum_msgs.user_id
    52.                     WHERE (topic_id, date) IN (SELECT topic_id, max(date) FROM forum_msgs GROUP BY topic_id)
    53.                 ) t3 ON t3.msg_topic_id=forum_topics.id
    54.                 WHERE (dir_id, date) IN (SELECT dir_id, max(date) FROM forum_topics GROUP BY dir_id)
    55.             ) t2 ON t2.dir_id=t1.id
     
  9. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.115
    Симпатии:
    1.244
    Адрес:
    там-сям
  10. Drema

    Drema Новичок

    С нами с:
    20 фев 2017
    Сообщения:
    117
    Симпатии:
    30
    Бедный сервачок.. не жалеете вы железку :) К тому же это + несколько ватт энергии впустую, а это жизнь одной птички. А ведь она могла жить.. скоро весна.
    Индексы хоть создайте, чтобы полегче было :)