|
Страница 1 из 1 [ Сообщений: 19 ] |
Автор |
Сообщение |
Арт Директор
новый человек
|
|
Предположим, мне необходимо для каждого пользователя получить из базы один его последний комментарий. Как это сделать рациональным способом?
Я делаю так (о, ужас!):
Код: select * from ( select users.user, comments.comment, comments.comment_date from users, comments where users.id = comments.user_id order by comments.comment_date desc ) c group by c.id order by c.comment_date desc
Наверняка кто-то уже сталкивался с проблемой group by + order
|
|
|
|
|
Арт Директор
новый человек
|
|
Crazy писал(а): | Арт Директор, order by имеет смысл ТОЛЬКО по тем полям, которые перечислены в group by.
Попробуй по-русски записать, что должен делать твой запрос, и поймешь его бессмысленность.
P.S. "select *" в сочетании с group by также признак того, что ты не понимаешь, что делаешь. Ни одна полноценная БД этот бред не пропустит, а MySQL вернет бредовый ответ. |
Я ж по-русски, вроде, написал: мне необходимо для каждого пользователя получить из базы один его последний комментарий. Плюс имя самого пользователя из users. В таблице comments находится множество комментариев для каждого пользователя из таблицы users. Поэтому нужно какую-то группирующую функцию применять (MAX(), DISTINCT()) или GROUP BY Я не спорю, что не понимаю, что делаю. Понимал бы, не спрашивал. Но задача, для человеческой логики, тривиальная. Не пойму, почему в имплементации БД все так усложняется?.. Ты вот если понимаешь, так подскажи! Кухан писал(а): | как-то сложно слишком неужели не работает DISTINCT по автору и сортировка комментариев в обратном порядке? |
DISTINCT по users.user отменяет сортировку по comments.comment_date
|
|
|
|
|
Crazy
Модератор
|
|
Цитата: | задача, для человеческой логики, тривиальная |
Согласно тривиальной человеческой логике запрос про "последний комментарий" должен содержать функцию MAX. Чего в первом запросе я не вижу. Цитата: | Не пойму, почему в имплементации БД все так усложняется? |
Если ты мыслишь в терминах множеств, то ничто не усложняется.
Начнем с простого: что должен вывести запрос, если у пользователя 3 (три) комментария с равной максимальной датой?
|
|
|
|
|
Арт Директор
новый человек
|
|
Crazy писал(а): | Цитата: | задача, для человеческой логики, тривиальная |
Согласно тривиальной человеческой логике запрос про "последний комментарий" должен содержать функцию MAX. Чего в первом запросе я не вижу. |
Эх, если бы все так просто было...
Код: -- -- Структура таблицы `test_users` --
CREATE TABLE `test_users` ( `id` int(10) unsigned NOT NULL auto_increment, `name` varchar(20) NOT NULL default '', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=3 ;
-- -- Дамп данных таблицы `test_users` --
INSERT INTO `test_users` (`id`, `name`) VALUES (1, 'Вася'), (2, 'Петя');
-- -- Структура таблицы `test_comments` --
CREATE TABLE `test_comments` ( `id` int(10) unsigned NOT NULL auto_increment, `user_id` int(10) unsigned NOT NULL default '0', `comment` varchar(30) NOT NULL default '', `comment_date` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=7 ;
-- -- Дамп данных таблицы `test_comments` --
INSERT INTO `test_comments` (`id`, `user_id`, `comment`, `comment_date`) VALUES (1, 1, 'Первый комментарий', '2008-02-19 19:29:09'), (2, 2, 'Первый комментарий', '2008-02-19 19:29:09'), (3, 1, 'Второй комментарий', '2008-02-19 19:29:24'), (4, 2, 'Второй комментарий', '2008-02-19 19:29:24'), (5, 1, 'Третий комментарий', '2008-02-19 19:29:40'), (6, 2, 'Третий комментарий', '2008-02-19 19:29:40');
А вот запрос: Код: SELECT max( comment_date ) AS date, name, COMMENT FROM test_users, test_comments WHERE test_users.id = user_id GROUP BY test_users.id
Ну а вот и ответ: Код: 2008-02-19 19:29:40 Вася Первый комментарий 2008-02-19 19:29:40 Петя Первый комментарий
Тут нельзя обойтись без GROUP BY(), которому плевать на твой MAX()
А ведь мне нужен ТРЕТИЙ комментарий для каждого пользователя.
Можешь написать запрос?
|
|
|
|
|
Crazy
Модератор
|
|
Арт Директор, ты продолжаешь буйно фантазировать вместо того, чтобы ответить на заданный тебе вопрос.
Во-первых, max прекрасно работает с group by. Строго по книжкам уровня "SQL для чайников". Правда, ты их не читал.
Во-вторых, в тех же книжках написано, что при использовании group by в select'е можно перечислять только колонки, упомянутые в group by и аггрегатные фунции (max, min, avg и т.п.). Запрос, нарушающий эти правила, в случае MySQL будет возращать некоторые произвольные данные. Что мы и наблюдаем.
Итак, я повторяю вопрос: что должен вывести запрос, если у пользователя 3 (три) комментария с равной максимальной датой?
|
|
|
|
|
Crazy
Модератор
|
|
Для экономии времени: очевидно, что получить список дат последних комментариев совсем нетрудно:
Код: select user_id, max(comment_date) as recent_comment_date from test_comments group by user_id Также очевидно, что если бы у нас была таблица recents с колонками user_id и recent_comment_date, то получить список последних комментариев тоже было бы нетрудно: Код: select * from recents r join test_comments c on r.recent_comment_date = c.comment_date and r.user_id = c.user_id;
Вот только... мы возвращаемся к вопросу, который я задал выше.
|
|
|
|
|
Арт Директор
новый человек
|
|
Crazy писал(а): | Итак, я повторяю вопрос: что должен вывести запрос, если у пользователя 3 (три) комментария с равной максимальной датой? |
Это самая смехотворная "проблема"
Можно сортировать по test_comments.id desc, который уникален. Вопрос отпал.
|
|
|
|
|
Crazy
Модератор
|
|
Арт Директор писал(а): | Это самая смехотворная "проблема" |
Когда сайт из-за смехотворных проблем принимает смехотворный вид -- лично мне становится смешно. Поскольку это всегда не мои сайты. Цитата: | Можно сортировать по test_comments.id desc, который уникален. Вопрос отпал. |
Эта фраза очень хорошо иллюстрирует причину, по которой написание запросов для БД кажется тебе запутанным делом. Вопрос был -- как оставить один из N. Ты предложил отсортировать. Отлично. Вот только количество от этого не изменилось. Если бы ты обращал внимание на то, как твои ответы соотносятся с вопросами -- БД было бы легче тебя понимать. Итак, мы имеем: 1. Два компонента запроса, которые я написал выше. 2. Твое предложение о сортировке. Отлично. Преврати п.2. в выражение для выделение одной строки из N и соедини с двумя моими фрагментами. И будет тебе счастье. Цитата: | можешь лаконичный запрос написать |
Я -- могу. Более того, он у меня написан и проверен. Ну ты же не думал, что я тебе его дам? Цитата: | ли так и будешь повторять то, что и так написано в онлайн-документации? |
Ну что ж еще делать, если ты не в состоянии сам ее прочитать? Кто ж еще выполнит эту гуманитарную миссию?
|
|
|
|
|
Crazy
Модератор
|
|
Арт Директор писал(а): | Еще одну таблицу создать - это не очень-то похоже на оптимизацию. |
А что, я где-то предложил создавать таблицу? Читаем внимательнее.
|
|
|
|
|
Crazy
Модератор
|
|
Арт Директор писал(а): | Я ведь могу сказать, что одним словом могу написать этот запрос. |
Можешь. Разница в том, что мне поверят все, а тебе -- никто. Так что практической пользы, акромя конфуза, это не принесет. Ну и последний hint: ты допустил принципиальную ошибку в условии задачи. Твоя постановка вопроса: Цитата: | необходимо для каждого пользователя получить из базы один его последний комментарий |
Это -- сферический конь вакууме. А вот почти то же самое, но приближенное к реальности: Цитата: | Необходимо на странице вывести список пользователей, показав для каждого его последний комментарий (или пустую строку, если комментариев не было) |
Юмор ситуации в том, что это совсем разные задачи. Вторая решается заметно проще, чем первая.
Удачи!
|
|
|
|
|
Арт Директор
новый человек
|
|
Crazy писал(а): | Можешь. Разница в том, что мне поверят все, а тебе -- никто. |
Я-то пост начал с работающего запроса, а ты просто зафлудил тему болтовней.
Пожалуй, и закончу его работающим запросом.
Код: select name, t1.comment from test_users, test_comments t1 left join test_comments t2 on t1.comment_date < t2.comment_date where t2.comment_date is null and t1.user_id = test_users.id
|
|
|
|
|
Crazy
Модератор
|
|
Арт Директор писал(а): | Я-то пост начал с работающего запроса, а ты просто зафлудил тему болтовней. |
Ну конечно, теперь это я виноват, что ты не можешь соединить всместе два запроса, которые тебе написали открытым текстом. Пойду всплакну от горя... Цитата: | Пожалуй, и закончу его работающим запросом. |
Да, это было бы неплохо. Вот только добавляем в таблицу еще одну запиcь:
Код: INSERT INTO `test_comments` (`id`, `user_id`, `comment`, `comment_date`) VALUES (7, 2, 'Четвертый комментарий', '2008-02-19 19:29:40'); ...и видим, что он нерабочий: Код: +------+-----------------------+ | name | comment | +------+-----------------------+ | Вася | Третий комментарий | | Петя | Третий комментарий | | Петя | Четвертый комментарий | +------+-----------------------+
А так -- да, сойдет.
|
|
|
|
|
Арт Директор
новый человек
|
|
Слушай, критик...
Код: select name, t1.comment from test_users, test_comments t1 left join test_comments t2 on t1.user_id = t2.user_id and t1.id < t2.id where t2.id is null and t1.user_id = test_users.id order by t1.id desc
Код: name | comment Петя | Четвертый комментарий Вася | Третий комментарий
Ты сам-то можешь хоть что-нить написать?
|
|
|
|
|
Crazy
Модератор
|
|
Арт Директор писал(а): | Слушай, критик... |
Друг мой, искренне советую не хамить. Цитата: | Ты сам-то можешь хоть что-нить написать? |
Это мы уже обсуждали.
|
|
|
|
|
|
Страница 1 из 1 [ Сообщений: 19 ] |
Уровень доступа: Вы не можете начинать темы. Вы не можете отвечать на сообщения. Вы не можете редактировать свои сообщения. Вы не можете удалять свои сообщения. Вы не можете добавлять вложения.
|
|