Подтвердить что ты не робот

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

4b9b3361

Ответ 1

Если вы выберете атрибуты, которые не используются в предложении группы и не являются агрегатами, результат не будет указан. Т.е. вы не знаете, из каких строк выбраны другие атрибуты. (Стандарт 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;

Ответ 2

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

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

Ответ 3

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

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 по мере необходимости.

Ответ 4

Возможно, это не лучший способ сделать это, но иногда функция group_concat() может быть полезна, она вернет строку всех агрегированных значений, отсортированных по вашему желанию и разделенных запятыми (связанное значение разделенные пробелом). Затем я использую функцию 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

Ответ 5

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

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