Ten rodzaj zapytania można przeformułować w sensie „największe-n-na-grupę”, gdzie chcesz, aby 10 najlepszych wyników na „grupę” było wartościami „foo”.
Proponuję zajrzeć na ten link który doskonale radzi sobie z tym pytaniem, zaczynając od sposobu, który ma sens, aby wykonać zapytanie i stopniowo je optymalizować.
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;
Jeśli chcesz to zrobić we wszystkich wszystkich poziomy foo
(np. wyobraź sobie, że robisz GROUP BY foo
), możesz pominąć where foo in ...
linia.
Zasadniczo zapytanie wewnętrzne (SELECT foo, score FROM tablebar WHERE foo IN ('abc','def') ORDER BY foo, score DESC
) chwyta foo
i score
z tabeli, zamawiając najpierw przez foo
a następnie punktacja malejąco.
@num := ...
po prostu zwiększa każdy wiersz, resetując do 1 dla każdej nowej wartości foo
. To znaczy @num
to tylko numer wiersza/pozycja (spróbuj samodzielnie uruchomić wewnętrzne zapytanie, aby zobaczyć, co mam na myśli).
Zewnętrzne zapytanie następnie wybiera wiersze, w których numer pozycji/wiersza jest mniejszy lub równy 10.
UWAGA:
Twoje oryginalne zapytanie z UNION
usuwa duplikaty, więc jeśli 10 najlepszych wyników dla foo='abc'
są 100, to zostanie zwrócony tylko jeden wiersz (ponieważ (foo,score)
para jest replikowana 10 razy). Ten zwróci duplikaty.