为 MySQL table 中的各行查找两个最大值

FInd two highest values for various rows in MySQL table

我有一个 MySQL table,sales,内容如下:

+----+-------+--------+
| id | name  | amount |
+----+-------+--------+
|  1 | Alice |     12 |
|  2 | Bob   |     10 |
|  3 | Alice |     14 |
|  4 | Bob   |      2 |
|  5 | Alice |      6 |
|  6 | Bob   |     23 |
|  7 | Bob   |      5 |
|  8 | Alice |     12 |
+----+-------+--------+

对于每个 name 我想找到具有最高 amount 的两行。换句话说,我想要一个 returns 这个结果的查询:

+----+-------+--------+
| id | name  | amount |
+----+-------+--------+
|  3 | Alice |     14 |
|  1 | Alice |     12 |
|  6 | Bob   |     23 |
|  2 | Bob   |     10 |
+----+-------+--------+

(结果中只应包括第 1 行和第 8 行之一。哪一个都无关紧要。)

我该怎么做?

编辑

添加了 table 中的第 8 行以阐明平局的处理。

如果你是运行 MySQL 8.0,只需使用window函数:

select *
from (
    select s.*,
        rank() over(partition by name order by amount desc) rn
    from sales s
) s
where rn <= 2
order by name, amount desc

这允许前 2 个关系(如果有)。

在早期版本中,一个选项使用子查询进行过滤:

select *
from sales s
where (select count(*) from sales s1 where s1.name = s.name and s1.amount > s.amount) < 2
order by name, amount desc

如果您使用的是现代 MySQL,row_number 应该就是您要找的。

select
  row_number() over (partition by [name] order by [amount] desc]) [rank], 
  id,
  name, 
  amount

这会添加必要的“排名”列,因此您只需 SELECT 来自 SELECT 作为您的 table 来源:

select id, name, amount
from ( -- the above query 
  select
    row_number() over (partition by [name] order by [amount] desc]) [rank], 
    id,
    name, 
    amount
) x
where x.[rank] <= 2
order by [name], [amount] desc

这是吹捧。

旧版本 MySQL 中的一个简单方法是:

select t.*
from t
where t.amount >= (select t2.amount
                   from t t2
                   where t2.name = t.name 
                   order by t2.amount desc
                   limit 1 offset 1
                  );

使用 (name, amount) 上的索引,这可能是最快的方法。