1. SQL / Говнокод #16836

    −124

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    SELECT * FROM (
        SELECT `comments`.`user`,
                       `comments`.`time`,
                       `comments`.`topic`,
                       `comments`.`id` AS `commid`,
                       `topic`.`name`,
                       `topic`.`id`,
                       `topic`.`translit`,
                       `topic`.`blog`,
                       `user`.`login`
        FROM `comments`, `topic`, `user`
        WHERE
        `comments`.`topic` IN (
            SELECT DISTINCT `topic`
            FROM `comments`
            ORDER BY `time` DESC)
            AND `topic`.`id` = `comments`.`topic`
            AND `user`.`id` = `comments`.`user`
            ORDER BY `comments`.`time` DESC
        ) `data`
        GROUP BY `data`.`topic`
        ORDER BY `data`.`time` DESC
        LIMIT 10

    Говнокод или необходимость?
    Не нашел способов сделать это одним запросом.

    Запостил: Efog, 11 Октября 2014

    Комментарии (35) RSS

    • //адекватных способов сделать это одним запросом.
      Ответить
    • WHERE
          `comments`.`topic` IN (
              SELECT DISTINCT `topic`
              FROM `comments`
              ORDER BY `time` DESC)
      А не тавтология ли это?
      Ответить
      • DISTINCT нельзя юзать, если выборка идет для 2+ полей. Только для одного. Поэтому пришлось извращаться.
        Ответить
        • WHERE же предназначено для фильтрации, а не для упорядочения. Тут целью было выбрать ровно одну запись для каждого comments.topic? А не лучше ли тогда применить группировку с лимитом?
          Ответить
          • Тут цель - выбрать последние откомментированые topic'и и автора последнего комментария в них.
            Ответить
            • SELECT DISTINCT `topic` FROM `comments` ORDER BY `time` DESC вернёт айдишники всех откомментированных топиков, какие только есть.

              WHERE `comments`.`topic` IN (список айдишников) ограничивает результаты... списком всех айдишников. Т. е. ничего полезного не делает. И даже ORDER BY `time` и DISTINCT никак на результат не повлияют.
              Ответить
              • >вернёт айдишники всех откомментированных топиков, какие только есть.
                LIMIT не заметил?
                Ответить
                • Заметил у внешнего запроса, у внутреннего нет.
                  Ответить
                  • О_О
                    Стоп, странно.
                    Оно ведь без этого не работает.
                    WTF?!
                    Ответить
                    • Для того, чтобы сджойнились таблички, нужен волшебный пинок в виде готового списка айдишников одной колонки? А если заменить слово WHERE на ON?
                      Ответить
                      • Если честно, не представляю, что за ON и как он работает.
                        Ответить
                        • Всё просто: ON - это WHERE в JOIN'ах
                          Ответить
                          • Просто никогда не пользовался JOIN'ами, даже не представляю, для чего они могут понадобиться.
                            Ответить
      • Не. Тавтология - это вот это:
        Ехал `comments` через `comments`,
        Видит `comments`: `comments`, `comments`!
        Сунул `comments` `comments` в `comments`,
        `Сomments` `comments` `comments` `comments`.
        Ответить
    • говнокод, безусловный
      автору выдать судебный запрет на приближение к субд ближе, чем на 1 км
      Ответить
      • > к субд
        Да он и так не с СУБД работает...
        Ответить
        • По сравнению с разными NoSQL (и даже с SQLite) волосатый друг — очень даже СУБД. И вообще если в качестве движка выбран не MyISAM, то можно привыкнуть уже на третий день.
          Ответить
          • В СУБД это выглядело бы примерно так: http://sqlfiddle.com/#!15/543c9/5

            Да простит меня d++, если я где-то косячу.
            Ответить
            • Ну хотя в этом конкретном случае айдишки уникальны и монотонно возрастают вместе со временем. Так что можно попроще: select max(id) from comments group by topic_id.
              Ответить
              • Кстати, почему-то даже в таком случае (когда айдишники монотонно возрастают вместе со временем) в Мистере Мускуле сортировка по времени тормозит, а по айдишникам — нет, хотя обе колонки проиндексированы. Почему?
                Ответить
              • > select max(id) from comments group by topic_id
                вы либо трусы наденьте, либо крестик снимите
                либо topic_id, max(id) либо group by

                > В СУБД это выглядело бы примерно так
                если стояла задача заселектить по одной штуке самого последнего комментария из каждого топика, то да, только order by time desc

                кроме того, интуитивно хочется как-то вписать дополнительной фильтр, сокращающий задачу субд,
                т.к. пока база маленькая, запрос будет нормально работать, но если в comments уже миллион записей, становится накладно сразу по всем бегать и сортировать - учитывая, что наверняка приложению прямо сейчас нужны ой далеко не все
                Ответить
                • > desc
                  Да, тупанул я.

                  > дополнительный фильтр
                  Ну, я так понял, что ОП мутит что-то типа ГК'шного стока. Что-то никакие фильтры тут в голову не приходят.

                  Имхо, если эти данные будут выбираться часто - можно немножко денормализовать базу, чтобы не искать эти максимумы-по-группе каждый раз...
                  Ответить
                  • > можно немножко денормализовать базу
                    именно, в topic засунуть пару лишних колонок о последнем комменте (время, айди), и поддерживать их состояние
                    если делать движок какого-нибудь суперпопулярного форума с миллионами постов, чтобы на страницу 68 попали правильно отсортированные темы с указанием последнего поста, и при этом запрос не исполнялся по 15 секунд
                    Ответить
                • нормальные рсудб умеют HAVING
                  select id,topic_id from comments group by topic_id having id=max(id)
                  Ответить
                  • С id проканает, т.к. оно всяко уникальное. С другими полями типа дат и цен - нет. Для них придется юзать ту фигню с over partition.
                    Ответить
                  • ты свой запрос выполнить пробовал, в нормальной рсубд?
                    все значения, которые употребляются в having, уже должны быть в сгруппированном результате - т.к. он работает после группировки
                    но группировка у тебя не сработает, т.к. либо id надо добавить в груп бай, что бред, либо id убрать из селект - и снова промах
                    Ответить
                    • В ненормальной тоже не запустилось :( Выдало пустое множество.
                      Ответить
    • в oracle, ms-sql или postgres сделал бы иначе
      а в говнобазе для неосиляторов майсцыкуль никак по другому
      Ответить

    Добавить комментарий