Получить топовый элемент за каждый год - PullRequest
1 голос
/ 09 апреля 2020

У меня есть данные с некоторыми записями. Используя mysql, я могу получить результат, сгруппированный по определенному c периоду (году) и пользователям и упорядоченный (в порядке убывания) по количеству видов.

SELECT YEAR(entry_date) AS period, uid AS user, COUNT(DISTINCT pid) AS species
FROM records
WHERE YEAR(entry_date)<YEAR(CURDATE())
GROUP BY period, uid
ORDER by period, species DESC

Пожалуйста, смотрите прикрепленный изображение результата . Но что, если я хочу получить ТОП ПОЛЬЗОВАТЕЛЯ (и количество видов) за КАЖДЫЙ год (строки, отмеченные красным)? Как я могу этого достичь?

Я могу справиться с этим позже в моем php коде, но было бы неплохо, чтобы это было уже рассмотрено в mysql запросе.

Спасибо за вашу помощь!

1 Ответ

1 голос
/ 09 апреля 2020

Если вы используете MySQL 8.0, вы можете использовать RANK() для ранжирования записей в разделах по годам по количеству видов, а затем отфильтровать верхнюю запись по группе:

SELECT *
FROM (
    SELECT 
        YEAR(entry_date) AS period, 
        uid AS user, 
        COUNT(DISTINCT pid) AS species,
        RANK() OVER(PARTITION BY YEAR(entry_date) ORDER BY COUNT(DISTINCT pid) DESC) rn
    FROM records
    WHERE entry_date < DATE_FORMAT(CURRENT_DATE, '%Y-01-01')
    GROUP BY period, uid
) t
WHERE rn = 1
ORDER by period

Это сохраняет верхние связи, если таковые имеются. Обратите внимание, что для дат в предложении WHERE используется индексный фильтр.

В более ранних версиях эквивалентным вариантом является фильтрация с предложением HAVING и коррелированным подзапросом:

SELECT 
    YEAR(entry_date) AS period, 
    uid AS user, 
    COUNT(DISTINCT pid) AS species
FROM records r
WHERE entry_date < DATE_FORMAT(CURRENT_DATE, '%Y-01-01')
GROUP BY period, uid
HAVING COUNT(DISTINCT pid) = (
    SELECT COUNT(DISTINCT r1.pid) species1
    FROM records r1
    WHERE YEAR(r1.entry_date) = period
    GROUP BY r1.uid
    ORDER BY species1 DESC
    LIMIT 1
)
ORDER by period
...