2009-05-19 2 views
4

Что мне нужно сделать, просто ... но его 3 утра и я, вероятно, не замечают очевидного.Как присоединиться к последней записи в таблице?

Im кодирование простого форума. В одной таблице хранятся названия, описания и т. Д., А в других - записи. В списке форумов, в котором показан список всех форумов, я хочу получить последнюю запись на каждом форуме и отобразить тему сообщения, постер и почтовый идентификатор и дату. Просто.

Единственная проблема заключается в том, что когда я присоединяюсь к таблице сообщений, она присоединяется к первой записи в таблице, а не к последней, которая будет обозначать последнее сообщение на этом форуме.

Вот упрощенный запрос, который получает список форумов + данных для «последнего» сообщения (которое теперь функционирует как «первый пост»).

SELECT forum_title, forum_id, post_subject, post_user, post_id, post_date FROM board_forums 
    LEFT JOIN board_posts 
    ON (forum_id = post_parentforum AND post_parentpost = 0) 
WHERE forum_status = 1 
GROUP BY forum_id 
ORDER BY forum_position 

Как это исправить?

ответ

5

Проблема, с которой вы сталкиваетесь, - это классический Неоднозначная группа по вопросу. Это особенно важно для MySQL, поскольку другие СУБД (и стандартный SQL) не позволят ваш запрос вообще. В вашем запросе не выполняется правило с одним значением, потому что вы не указали все неагрегированные столбцы в GROUP BY.

Вот решение демонстрирует мой любимый способ получить наибольшую строку в группе:

SELECT f.forum_title, f.forum_id, p1.post_subject, p1.post_user, 
    p1.post_id, p1.post_date 
FROM board_forums f 
LEFT JOIN board_posts p1 
    ON (f.forum_id = p1.post_parentforum AND p1.post_parentpost = 0) 
LEFT JOIN board_posts p2 
    ON (f.forum_id = p2.post_parentforum AND p2.post_parentpost = 0 
     AND p1.post_id < p2.post_id) 
WHERE p2.post_id IS NULL AND f.forum_status = 1 
ORDER BY f.forum_position; 

Если p2.post_id IS NULL, это означает, что ни одна должность не будет найден в p2, которая больше, чем пост, найденного в p1.

Ergo, p1 является последним сообщением (при условии, что post_id - автоинкремент).


Re комментарий:

Незначительные проблемы с этим. post_id с самым высоким ID не обязательно является последним сообщением.

Нет проблем. Просто используйте столбец, который, как гарантируется, отличает предыдущую запись от более поздней публикации. Вы указываете post_date. В случае связей вам придется разорвать связи с другим столбцом (или столбцами), который обязательно будет в хронологическом порядке.

LEFT JOIN board_posts p2 
    ON (f.forum_id = p2.post_parentforum AND p2.post_parentpost = 0 
    AND (p1.post_date < p2.post_date 
     OR p1.post_date = p2.post_date AND p1.post_millisecond < p2.post_millisecond)) 
+1

Я рад, что вы упомянули проблему - я вернулся к этому вопросу с полдюжины раз, но даже не мог понять, как запрос работает, как это было написано, так что сдался. Не будучи пользователем MySQL, я не понимал, что это позволит вам скользить без фиксации этой GROUP BY. Теперь я знаю! :) – TML

+0

Да. MySQL доверяет, что вы знаете, что делаете, и что вы следуете правилу однозначности. SQLite также имеет такое же поведение. Если вы пишете запрос с неоднозначными столбцами (более одного значения для каждой группы), РСУБД выбирает значение произвольно. MySQL выбирает значение из «первой» строки (в порядке физического хранения строк). Кстати, SQLite выбирает значение из «последней» строки. –

+0

Незначительная проблема с этим. post_id с самым высоким ID не обязательно является последним сообщением. Если будет создан новый поток, он будет иметь последний идентификатор, и в этом случае ваш пример будет работать. Но как только ответ делается на более старый поток (с более низким идентификатором), он больше не функционирует так, как предполагалось, и все еще показывает therad с самым высоким ID. Необходимо показать его на основе post_date. – 2009-05-19 07:22:06