MySQL Query, Join и Myself, или как я всегда прошёл сложный путь - PullRequest
0 голосов
/ 24 мая 2009

Я создаю небольшой форум.

Попытка выполнить запрос SElECT... JOIN... также забирает информацию об отдельных сообщениях плюс последний ответ (если есть). Как часть моего желания сделать все трудным путем, это охватывает пять таблиц (указываются только столбцы, относящиеся к этой проблеме)

commentInfo    referenceID | referenceType | authorID | create
postit         id | title
postitInfo     referencePostitID | create | authorID
user           id | username | permission
userInfo       referenceUserID | title

Итак, я запускаю этот запрос SELECT... JOIN..., чтобы получить самые последние темы и их последние ответы.

SELECT DISTINCT
    t1.id, t1.title, t2.create, t2.lastEdit, t2.authorID, t3.username, 
    t4.title AS userTitle, t3.permission, t5.create AS commentCreate, 
    t5.authorID AS commentAuthor, t6.username AS commentUsername, 
    t6.permission AS commentPermission
FROM rantPostit AS t1
LEFT JOIN (rantPostitInfo AS t2) 
    ON ( t1.id = t2.referencePostitID)
LEFT OUTER JOIN (rantUser as t3, rantUserInfo as t4) 
    ON (t2.authorId = t3.id AND t4.referenceUserId = t2.authorId)
LEFT OUTER JOIN (rantCommentInfo as t5, rantUser as t6) 
    ON (t5.referenceType = 8 AND t5.referenceID = t1.id AND t6.id = t5.authorID)
ORDER BY t2.create DESC, t5.create DESC

Теперь это возвращает сообщения в теме. Скажем, у меня есть два из них, он возвращает оба хорошо. Скажем, у меня есть восемь ответов на первый, он вернет 9 записей (по одному для каждой темы + ответ, а другой - без ответов). Итак, я предполагаю, что моя проблема заключается в следующем: я не знаю, что делать, чтобы ограничить число возвращений в последнем предложении LEFT OUTER JOIN только самыми последними или просто вычеркнуть наименее последние из окна.

(Да, я понимаю, что предложение ORDER BY... испорчено, так как сначала упорядочит его по дате создания поста, а затем по дате создания комментария. Да, я понимаю, что могу упростить все свои проблемы, добавив два поля в postitInfo, lastCommentCreate и lastCommentCreateID, и они обновляются каждый раз при получении ответа, но ... мне нравится трудный путь.)

Так что я делаю не так?

Или это такая бессмысленная проблема, что меня нужно обвести вокруг сарая и бить молотком?

Ответы [ 2 ]

1 голос
/ 24 мая 2009

Расщепления между post и postInfo и таблицами user и userInfo, похоже, ничего здесь не делают, кроме запутанных вещей. Чтобы лучше увидеть решения, давайте рассмотрим все по существу: таблица Posts (с первичным ключом id, дата создания date и другие поля) и таблица Comments (с первичным ключом id, внешний ключ refId, ссылающийся на Posts, уникальная дата создания date и другие поля); мы хотим видеть все сообщения, каждое с последним комментарием, если оно есть (первичные ключи id извлеченных строк таблицы и другие поля, конечно, могут быть контекстно использованы в SELECT для извлечения и отображения дополнительной информации пока, но это не меняет структуру ядра, и упрощение вещей до структуры ядра должно помочь проиллюстрировать решения). Я предполагаю, что дата создания комментария уникальна, иначе «последний комментарий» может быть неоднозначным (конечно, эта неоднозначность может быть произвольно усечена другими способами, выбирая один элемент из набора «последних комментариев» к данному сообщению ).

Итак, вот один подход:

SELECT Posts.id, Comments.id FROM Posts
LEFT OUTER JOIN Comments on (Posts.id = Comments.refId)
WHERE Comments.create IS NULL OR (
      Comments.create = (SELECT create FROM Comments
                         WHERE refID = Posts.id
                         ORDER BY create DESC
                         LIMIT 1)
) /* add ORDER BY &c to taste;-) */

идея: для каждого поста нам нужен «нулевой комментарий» (если к нему не было комментариев) или комментарий, дата создания которого является самой высокой среди тех, кто ссылается на пост; здесь внутренний SELECT заботится о поиске этой «самой высокой» даты создания. Таким образом, в том же духе, внутренний выбор может быть SELECT MAX(create) FROM Comments WHERE refID = Posts.id, что, вероятно, предпочтительнее (как более короткий и более прямой, и, возможно, более быстрый).

0 голосов
/ 24 мая 2009

Похоже, что последнее LEFT JOIN - единственное, которое может возвращать несколько строк. Если это правда, вы можете просто использовать LIMIT 5, чтобы получить последние пять комментариев:

 ORDER BY t5.create DESC
 LIMIT 5

Если нет, то очень простым решением было бы получить комментарии с помощью отдельного запроса:

SELECT *
FROM rantCommentInfo t5
    ON t5.referenceType = 8 
    AND t5.referenceid = t1.id
LEFT OUTER JOIN rantUser t6
    ON t6.id = t5.authorID
ORDER BY CommentCreate
WHERE t5.referenceid = YourT1Id
LIMIT 5

Не могу придумать способ сделать это в одном запросе без ROW_NUMBER, который MySQL не поддерживает.

...