Вы можете сделать это с помощью переменных:
SELECT
id,
title,
group_id,
votes
FROM (
SELECT
id,
title,
group_id,
votes,
@rn := CASE WHEN @prev = group_id THEN @rn + 1 ELSE 1 END AS rn,
@prev := group_id
FROM table1, (SELECT @prev := -1, @rn := 0) AS vars
ORDER BY group_id DESC, votes DESC
) T1
WHERE rn <= 3
ORDER BY group_id, votes DESC
Это в основном аналогично следующему запросу в базах данных, которые поддерживают ROW_NUMBER:
SELECT
id,
title,
group_id,
votes
FROM (
SELECT
id,
title,
group_id,
votes,
ROW_NUMBER() OVER (PARTITION BY group_id ORDER BY votes DESC) AS rn
FROM student
) T1
WHERE rn <= 3
ORDER BY group_id, votes DESC
Но так как MySQL не поддерживает ROW_NUMBER, вы должны смоделировать его, и для этого нужны переменные. Два запроса в остальном идентичны. Постарайтесь сначала понять второй запрос, и, надеюсь, первый будет иметь больше смысла.