一尘不染

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

mysql

是否有更好的方法从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)

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


阅读 213

收藏
2020-05-17

共1个答案

一尘不染

这种查询可以用“每组最大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)抓住fooscore从该表中,由第一排序foo,然后评分降序。

@num := ...刚刚增加的每一行,重置为1的每个新值foo。也就是说,@num仅是行号/行数(尝试自行运行内部查询以了解我的意思)。

然后,外部查询选择行/行数小于或等于10的行。

注意:

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

2020-05-17