SQL-запрос, чтобы найти 3 лучших в категории

Обращаемся ко всем энтузиастам sql! Краткая информация: использование PostgreSQL.

У меня есть запрос, который возвращает максимальное количество лайков для пользователя в каждой категории. Сейчас я хочу показать трех пользователей с наибольшим количеством лайков в каждой категории.

Полезный ресурс использовал этот пример для решения проблемы:

select type, variety, price
from fruits
where (
   select count(*) from fruits as f
   where f.type = fruits.type and f.price <= fruits.price
) <= 2;

Я понимаю это, но в моем запросе используются объединения, и я тоже новичок, поэтому мне не удалось эффективно использовать эту информацию.

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

SELECT category, username, MAX(post_likes) FROM (
SELECT c.name category, u.username username, SUM(p.like_count) post_likes, COUNT(*) post_num
FROM categories c
JOIN topics t ON c.id = t.category_id
JOIN posts p ON t.id = p.topic_id
JOIN users u ON u.id = p.user_id
GROUP BY c.name, u.username) AS leaders
WHERE post_likes > 0
GROUP BY category, username
HAVING MAX(post_likes) >= (SELECT SUM(p.like_count) 
                          FROM categories c 
                          JOIN topics t ON c.id = t.category_id 
                          JOIN posts p ON t.id = p.topic_id 
                          JOIN users u ON u.id = p.user_id WHERE c.name = leaders.category
GROUP BY u.username order by sum desc limit 1)
ORDER BY MAX(post_likes) DESC;

Любая помощь будет принята с благодарностью. Мне трудно осмыслить эту проблему. Благодарить!


person stevenpslade    schedule 07.12.2015    source источник


Ответы (1)


Если вы хотите, чтобы в каждой категории было больше лайков, используйте оконные функции:

SELECT cu.*
FROM (SELECT c.name as category, u.username as username, 
             SUM(p.like_count) as post_likes, COUNT(*) as post_num,
             ROW_NUMBER() OVER (PARTITION BY c.name ORDER BY COUNT(*) DESC) as seqnum
      FROM categories c JOIN
           topics t
           ON c.id = t.category_id JOIN
           posts p
           ON t.id = p.topic_id JOIN
           users u
           ON u.id = p.user_id
      GROUP BY c.name, u.username
     ) cu
WHERE seqnum <= 3;

Это всегда возвращает три строки для каждой категории, даже если есть связи. Если вы хотите сделать что-то еще, подумайте о DENSE_RANK() или RANK() вместо ROW_NUMBER().

Также используйте as для псевдонимов столбцов в предложении FROM. Хотя это необязательно, однажды вы опустите запятую и будете благодарны за то, что привыкли использовать as.

person Gordon Linoff    schedule 07.12.2015