Този вид заявка може да бъде префразирана в смисъл на „най-голям 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 пъти). Този ще върне дубликати.