В версии MySQL до 8.0 мы можем эмулировать аналитические функции, используя пользовательские переменные в тщательно обработанных запросах.Обратите внимание, что мы зависим от поведения пользовательских переменных, которое не гарантируется (задокументировано в Справочном руководстве MySQL).
SELECT @rn := IF(c.genre_name=@prev_genre,@rn+1,1) AS rn
, @prev_genre := c.genre_name AS genre_name
, c.actor_id AS actor_id
, c.num_mov AS num_mov
FROM ( SELECT @prev_genre := NULL, @rn := 0 ) i
CROSS
JOIN ( SELECT g.genre_name
, a.actor_id
, COUNT(1) AS num_mov
FROM actor a
JOIN role r
ON r.actor_id = a.actor_id
JOIN movie m
ON m.movie_id = r.movie_id
JOIN movie_has_genre mg
ON mg.movie_id = m.movie_id
JOIN genre g
ON g.genre_id = mg.genre_id
GROUP
BY g.genre_name
, a.actor_id
ORDER
BY g.genre_name
, COUNT(1) DESC
, a.actor_id
) c
ORDER
BY c.genre_name
, c.num_mov DESC
, c.actor_id
HAVING rn <= 4
Литерал 4
в конце запроса представляет значение N
в вопросе.
В MySQL 8.0 мы можем использовать недавно введенные аналитические функции, чтобы получить эквивалентный результат:
SELECT ROW_NUMBER() OVER(PARTITION BY c.genre_name ORDER BY c.num_mov DESC, c.actor_id)
AS rn
, c.genre_name AS genre_name
, c.actor_id AS actor_id
, c.num_mov AS num_mov
FROM ( SELECT g.genre_name
, a.actor_id
, COUNT(1) AS num_mov
FROM actor a
JOIN role r
ON r.actor_id = a.actor_id
JOIN movie m
ON m.movie_id = r.movie_id
JOIN movie_has_genre mg
ON mg.movie_id = m.movie_id
JOIN genre g
ON g.genre_id = mg.genre_id
GROUP
BY g.genre_name
, a.actor_id
ORDER
BY g.genre_name
, COUNT(1) DESC
, a.actor_id
) c
ORDER
BY c.genre_name
, c.num_mov DESC
, c.actor_id
HAVING rn <= 4