Eso fue desafiante.
Para resolverlo usé varios métodos:
- Una Declaración CASE para convertir el lugar del grupo entre los 3 primeros en puntos.
- Numeración de filas con una variable .
- INTERIOR Y IZQUIERDA ÚNETE para combinar los resultados.
La siguiente consulta se probó en su violín y funciona:
SELECT t1.`id`, t1.`name`, t1.`group1`,
t1.`section`, t1.`MARKS`, `t_group_points`.`points`
FROM `students` t1
#--- Join groups' points to the students
LEFT JOIN (
(
#---- Join all groups and give points to top 3 avg's groups ----
SELECT `t4`.`group1`, `t_points`.`points`
FROM (SELECT `t3`.`group1`, AVG(`t3`.`marks`) AS `avg`
FROM `students` `t3`
WHERE (`t3`.`section` = 'class1') AND
(`t3`.`group1` IS NOT NULL)
GROUP BY `t3`.`group1`) `t4`
INNER JOIN (
#---------- Select top 3 avarages ----------
(SELECT `top`.`avg`,
#-- Convert row number to points ---
CASE @curRow := @curRow + 1
WHEN '1' THEN 5
WHEN '2' THEN 3
WHEN '3' THEN 1
ELSE NULL END 'points'
FROM (SELECT DISTINCT `t_avg`.`avg`
FROM (SELECT `t2`.`group1`, AVG(`t2`.`marks`) AS `avg`
FROM `students` `t2`
WHERE (`t2`.`section` = 'class1') AND
(`t2`.`group1` IS NOT NULL)
GROUP BY `group1`) `t_avg`
ORDER BY `avg` DESC
LIMIT 0, 3) `top`, (SELECT @curRow:=0) r
) AS `t_points`)
ON (`t_points`.`avg` = `t4`.`avg`)
) AS `t_group_points`)
ON (`t_group_points`.`group1` = `t1`.`group1`)