У меня есть блог Spring MVC с функциями голосования по почте и комментариям.Я хочу вернуть трех лучших пользователей в зависимости от количества голосов, полученных ими за все свои сообщения и комментарии.
таблиц:
пользователей u [id, имя пользователя]
сообщений p [id, u.id]
комментарии c [id, p.id, u.id]
post_votes pv [p.id, u.id, тип (1 или -1)]
comment_votes cv [c.id, u.id, type (1 или -1)]
Следующее утверждение дает мне общее количество голосов на пользователя, запрашивая две отдельные таблицы голосования и затем суммируя вместе:
SELECT
(SELECT SUM(type)
FROM posts_votes pv
JOIN posts p ON p.id = pv.post_id
JOIN users u ON u.id = p.user_id
WHERE u.id LIKE ?1)
+
(SELECT SUM(type)
FROM comments_votes cv
JOIN comments c ON c.id = cv.comment_id
JOIN users u ON u.id = c.user_id
WHERE u.id LIKE ?1)
Это прекрасно работает с предложением WHERE для каждого идентификатора пользователя ... Но сейчас я пытаюсь найти только трех лучших пользователей, которые имеют наибольшее количество голосов, и у меня слишком много трудностей.Это то, что я имею до сих пор:
SELECT u.id, u.username, IFNULL(SUM(pv.type), 0) AS totalPostVotes
FROM posts_votes pv
JOIN posts p ON p.id = pv.post_id
JOIN users u ON u.id = p.user_id
GROUP BY u.id ORDER BY totalPostVotes DESC LIMIT 3
Вышеприведенное утверждение работает само по себе, давая мне: u.id, u.username и totalPostVote в порядке убывания.То же самое, что ниже для комментариев:
SELECT u.id, u.username, IFNULL(SUM(cv.type), 0) AS totalCommentVotes
FROM comment_votes cv
JOIN comments c ON c.id = cv.comment_id
JOIN users u ON u.id = c.user_id
GROUP BY u.id ORDER BY totalCommentVotes DESC LIMIT 3
Отлично!Но я хочу, чтобы результат третьего столбца SUM был по существу «totalVotes» и содержал сумму обоих этих подзапросов.Тогда я сгруппируюсь по u.id ЗАКАЗАТЬ ПО totalVotes DESC LIMIT 3.
Примерно так:
SELECT u.id, u.username, SUM(
(SELECT IFNULL(SUM(pv.type), 0) AS totalPostVotes
FROM posts_votes pv
JOIN posts p ON p.id = pv.post_id
JOIN users u ON u.id = p.user_id
GROUP BY u.id ORDER BY totalPostVotes DESC LIMIT 1)
+
(SELECT IFNULL(SUM(cv.type), 0) AS totalCommentVotes
FROM comments_votes cv
JOIN comments c ON c.id = cv.comment_id
JOIN users u ON u.id = c.user_id
GROUP BY u.id ORDER BY totalCommentVotes DESC LIMIT 1))
AS totalVotes from users u
GROUP BY u.id, u.username ORDER BY totalVotes DESC LIMIT 3
id | username | totalVotes
2 user2 11
1 user1 11
29 user29 11
То, что происходит, является результатом того, что totalVotes действительно является правильным подсчетом голосов, 11для «верхнего» пользователя, но ни один из этих пользователей не является настоящим топ-пользователем, и правильный голос повторяется 3 раза под видом других пользователей.Я даже не уверен, как пользователи сортируются в этот момент, потому что они не в порядке, который я узнаю.
Подзапросы работают отдельно (они дают мне правильного пользователя), когда я добавляю SELECT "u.id, u.username" IFNULL (SUM ()), но затем, если я запускаю весь блок, я получаю ошибку«Операнд должен содержать 1 столбец (и)». Поэтому я удаляю их и возвращаюсь только к SELECT IFNULL (SUM ())
Я также замечаю, что подзапросам разрешен только LIMIT 1. Как бы я получил верх3, тогда?Должен ли я где-нибудь сделать СОЮЗ или достаточно «+»?Это довольно запутанно.Может кто-нибудь, пожалуйста, помогите мне с этим?Любая помощь приветствуется.Заранее спасибо!
Обновлен код, спасибо Питеру:
SELECT
u.username,
pv_sum.total AS postTotal,
cv_sum.total AS commentTotal,
IFNULL(pv_sum.total, 0) + IFNULL(cv_sum.total, 0) as totalVotes
FROM users u
LEFT JOIN (
SELECT p.user_id, IFNULL(SUM(pv.type), 0) AS total
FROM posts p
JOIN posts_votes pv ON pv.post_id = p.id
GROUP BY p.user_id
) pv_sum ON pv_sum.user_id = u.id
LEFT JOIN (
SELECT c.user_id, IFNULL(SUM(cv.type), 0) AS total
FROM comments c
JOIN comments_votes cv ON cv.comment_id = c.id
GROUP BY c.user_id
) cv_sum ON cv_sum.user_id = u.id
GROUP BY u.username, postTotal, commentTotal
ORDER BY totalVotes DESC LIMIT 3;