MySQL为表中的每个人选择前X个记录

Exu*_*ery 4 mysql greatest-n-per-group

有没有更好的方法从MySQL表中获得多个"前X"结果?当不同foo的数量很小时,我可以通过联合轻松完成此任务:

(SELECT foo,score FROM tablebar WHERE (foo = 'abc') ORDER BY score DESC LIMIT 10) 
UNION 
(SELECT foo,score FROM tablebar WHERE (foo = 'def') ORDER BY score DESC LIMIT 10)
Run Code Online (Sandbox Code Playgroud)

我显然可以继续为foo的每个值添加联合.但是,当foo有500多个不同的值时,这是不实际的,我需要每个的前X个.

mat*_*fee 10

这种查询可以在"每组最大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;
Run Code Online (Sandbox Code Playgroud)

如果你想在所有级别执行此操作foo(即想象做一个GROUP BY foo),你可以省略该where foo in ...行.

基本上内部查询(SELECT foo, score FROM tablebar WHERE foo IN ('abc','def') ORDER BY foo, score DESC)抓取fooscore从表中先排序foo然后降序.

@num := ...刚刚增加的每一行,重置为1的每个新值foo.也就是说,@num只是一个行号/等级(尝试单独运行内部查询以查看我的意思).

外部查询然后选择排名/行号小于或等于10的行.

注意:

您的原始查询UNION删除了重复项,因此如果前10个分数foo='abc'都是100,则只返回一行(因为该(foo,score)对被复制10次).这个将返回重复.