Этот тип запроса может быть перефразирован в смысле «наибольший n на группу», где вы хотите, чтобы первые 10 баллов на «группу» были значениями «foo».
Я предлагаю вам взглянуть на эту ссылку , которая прекрасно справляется с этим вопросом, начиная со способа, который имеет смысл выполнить ваш запрос, и постепенно оптимизируя его.
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;
Если вы хотите выполнить это на всех уровнях foo
(т.е. представьте, что делаете GROUP BY foo
), вы можете опустить строку where foo in ...
.
В основном внутренний запрос (SELECT foo, score FROM tablebar WHERE foo IN ('abc','def') ORDER BY foo, score DESC
) захватывает foo
и score
из таблицы, упорядочивая сначала по foo
, а затем по убыванию.
@num := ...
просто увеличивает каждую строку, сбрасывая в 1 для каждого нового значения foo
. То есть @num
- это просто номер строки / ранг (попробуйте выполнить внутренний запрос самостоятельно, чтобы понять, что я имею в виду).
Затем внешний запрос выбирает строки, где ранг / номер строки меньше или равен 10.
Примечание:
Ваш исходный запрос с UNION
удаляет дубликаты, поэтому, если все первые 10 баллов для foo='abc'
равны 100, будет возвращена только одна строка (поскольку пара (foo,score)
реплицируется 10 раз). Этот вернет дубликаты.