This type of query can be rephrased in the sense of "highest-n-per-group", where you want the top 10 points for a "group" to be "foo"
I suggest you take a look at this link , which deals with this question surprisingly, starting with the fact that it makes sense to fulfill your request and gradually optimize it.
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;
If you want to do this at all levels of foo
(i.e. imagine GROUP BY foo
), you can omit the line where foo in ...
Basically, an internal query ( SELECT foo, score FROM tablebar WHERE foo IN ('abc','def') ORDER BY foo, score DESC
) grabs foo
and score
from the table, first ordering foo
and then evaluating the decrease.
@num := ...
just increments each line, resetting to 1 for each new value of foo
. That is, @num
is just a line number / rank (try running an internal query yourself to see what I mean).
The external query then selects rows where the rank / row number is less than or equal to 10.
Note:
Duplicates are removed in the original query with UNION
, so if the top 10 points for foo='abc'
are 100, then only one row is returned (since the pair (foo,score)
replicated 10 times). This will return duplicates.