php mysql Group Для получения последней записи, а не первой записи

Стол:

(`post_id`, `forum_id`, `topic_id`, `post_time`) (79, 8, 4, '2012-11-19 06:58:08'); (80, 3, 3, '2012-11-19 06:58:42'), (81, 9, 9, '2012-11-19 06:59:04'), (82, 11, 6, '2012-11-19 16:05:39'), (83, 9, 9, '2012-11-19 16:07:46'), (84, 9, 11, '2012-11-19 16:09:33'), 

Запрос:

 SELECT post_id, forum_id, topic_id FROM posts GROUP BY topic_id ORDER BY post_time DESC LIMIT 5 

Результаты:

 [0] => [post_id] => 84 [forum_id] => 9 [topic_id] => 11 [1] => [post_id] => 82 [forum_id] => 11 [topic_id] => 6 [2] => [post_id] => 81 [forum_id] => 9 [topic_id] => 9 [3] => [post_id] => 80 [forum_id] => 3 [topic_id] => 3 [4] => [post_id] => 79 [forum_id] => 8 [topic_id] => 4 

Проблема:

Как переписать запрос так, чтобы он возвращал post_id -> 83 вместо post_id -> 81?

Они оба имеют одинаковые идентификаторы форума и темы, но post_id -> 81 имеет более старую дату, чем post_id -> 83.

Но похоже, что Group By получает «первую» запись, а не «самую новую».

Я попытался изменить запрос на

 SELECT post_id, forum_id, topic_id, MAX(post_time) 

но это возвращает как post_id 81, так и 83

Если вы выбираете атрибуты, которые не используются в предложении group, и не являются агрегатами, результат не указан. Т.е. вы не знаете, из каких строк выбираются другие атрибуты. (Стандарт sql не позволяет такие запросы, но MySQL более расслаблен).

Затем запрос должен быть написан, например, как

 SELECT post_id, forum_id, topic_id FROM posts p WHERE post_time = (SELECT max(post_time) FROM posts p2 WHERE p2.topic_id = p.topic_id AND p2.forum_id = p.forum_id) GROUP BY forum_id, topic_id, post_id ORDER BY post_time DESC LIMIT 5; 

или

 SELECT post_id, forum_id, topic_id FROM posts NATURAL JOIN (SELECT forum_id, topic_id, max(post_time) AS post_time FROM posts GROUP BY forum_id, topic_id) p ORDER BY post_time LIMIT 5; 

Это не очень красиво, но это работает:

 SELECT * FROM (SELECT post_id, forum_id, topic_id FROM posts ORDER BY post_time DESC) as temp GROUP BY topic_id 

попробуйте что-нибудь вроде

 SELECT post_id, forum_id, topic_id FROM (SELECT post_id, forum_id, topic_id FROM posts ORDER BY post_time DESC) GROUP BY topic_id ORDER BY topic_id desc LIMIT 0,5 

при необходимости измените order by и limit .

Возможно, это не лучший способ сделать это, но иногда функция group_concat () может быть userfull, она вернет строку из всех агрегированных значений, отсортированных так, как вы хотите, и разделенных запятой (связанное значение разделяется пробелом). Затем я использую функцию SPLIT_STRING () для вырезания первого идентификатора в строке.

 SELECT post_id, SPLIT_STRING( group_concat( forum_id, post_time ORDER BY post_time DESC ) ,' ',1 )as forum_id, SPLIT_STRING( group_concat( topic_id, post_time ORDER BY post_time DESC ) ,' ',1 )as topic_id , FROM posts GROUP BY topic_id ORDER BY post_time DESC LIMIT 5 

Таким образом, агрегированный forum_id, post_time будет выглядеть следующим образом:

81 2012-11-19 06: 59: 04,83 2012-11-19 16:07:46

Поэтому вам нужно работать со строковым представлением целых чисел и пар datetime, каждая пара разделяется запятой, поэтому я использовал эту функцию, чтобы получить первый INT:

 CREATE FUNCTION SPLIT_STRING(str VARCHAR(255), delim VARCHAR(12), pos INT) RETURNS VARCHAR(255) RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(str, delim, pos), LENGTH(SUBSTRING_INDEX(str, delim, pos-1)) + 1), delim, ''); 

Примечание: функция SPLIT_STRING (str, delim, pos) была найдена здесь: Эквивалент функции explode ( ) для работы со строками в MySQL

Это также отлично подходит для вас.

 SELECT * FROM ( SELECT post_id, forum_id, topic_id FROM posts ORDER BY post_time DESC LIMIT 5 ) customeTable GROUP BY topic_id