Ce type de requête peut être reformulé dans un sens "plus grand-n-par-groupe", où vous voulez que les 10 meilleurs scores par "groupe" soient des valeurs de "foo".
Je vous suggère de jeter un œil à ce lien qui traite cette question à merveille, en commençant par une manière logique d'effectuer votre requête et en l'optimisant progressivement.
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 vous vouliez effectuer cela sur tous niveaux de foo
(c'est-à-dire imaginez faire un GROUP BY foo
), vous pouvez omettre le where foo in ...
ligne.
Fondamentalement, la requête interne (SELECT foo, score FROM tablebar WHERE foo IN ('abc','def') ORDER BY foo, score DESC
) saisit foo
et score
à partir du tableau, en triant d'abord par foo
puis score décroissant.
Le @num := ...
augmente simplement chaque ligne, réinitialisant à 1 pour chaque nouvelle valeur de foo
. C'est-à-dire @num
est juste un numéro de ligne/rang (essayez d'exécuter la requête interne seule pour voir ce que je veux dire).
La requête externe sélectionne ensuite les lignes dont le numéro de rang/ligne est inférieur ou égal à 10.
REMARQUE :
Votre requête d'origine avec UNION
supprime les doublons, donc si les 10 meilleurs scores pour foo='abc'
sont tous 100 alors une seule ligne sera retournée (puisque le (foo,score)
paire est répliquée 10 fois). Celui-ci renverra des doublons.