Este tipo de consulta se puede reformular en el sentido de "mayor n-por-grupo", donde desea que las 10 puntuaciones principales por "grupo" sean valores de 'foo'.
Le sugiero que eche un vistazo a este enlace que trata esta pregunta maravillosamente, comenzando con una forma que tiene sentido para realizar su consulta y optimizándola gradualmente.
set @num := 0, @foo := '';
select foo, score
from (
select foo, score,
@num := if(@foo = foo, @num + 1, 1) as row_number,
@foo := foo as dummy
from tablebar
where foo IN ('abc','def')
order by foo, score DESC
) as x where x.row_number <= 10;
Si quisiera realizar esto en todos niveles de foo
(es decir, imagina hacer un GROUP BY foo
), puede omitir el where foo in ...
línea.
Básicamente, la consulta interna (SELECT foo, score FROM tablebar WHERE foo IN ('abc','def') ORDER BY foo, score DESC
) agarra foo
y score
de la mesa, ordenando primero por foo
y luego puntuación descendente.
El @num := ...
simplemente aumenta cada fila, reiniciando a 1 para cada nuevo valor de foo
. Es decir, @num
es solo un número de fila/rango (intente ejecutar la consulta interna por sí sola para ver a qué me refiero).
La consulta externa luego selecciona las filas donde el rango/número de fila es menor o igual a 10.
NOTA:
Tu consulta original con UNION
elimina duplicados, por lo que si los 10 mejores puntajes para foo='abc'
son todos 100, solo se devolverá una fila (ya que (foo,score)
par se replica 10 veces). Este devolverá duplicados.