SQL查询返回由另一列“分组”的一列的三个最高值

时间:2012-04-23 20:01:15

标签: mysql sql

假设我有一张这样的表:

Player  Score
A       5
B       4
A       3
B       2
A       1
B       1
A       2
B       3
A       4
B       5

我需要一个SQL查询,它将按玩家的“分组”降序返回每位玩家的三个最高分数,即

Player  Score
A       5
A       4
A       3
B       5
B       4
B       3

非常感谢任何指示。

4 个答案:

答案 0 :(得分:3)

这是一种老式的(读取:基本的sql)方法,每组产生top-n。你可以在小组条件下加入表格(这里是玩家)并选择右侧得分较高的记录;如果有三个或更少这样的记录,则该行是每组前n行中的一行。

select player.player, player.score
from Player
left join Player p2
on p2.player = player.player
  and p2.score > player.score
group by player.player, player.score
having count(distinct p2.score) < 3
order by 1, 2 desc

您可能检查的替代版本,使用不存在:

select player, score
from player
where not exists
(
  select p2.player
  from Player p2
  where p2.player = player.player
  and p2.score > player.score
  group by p2.player
  having count(distinct p2.score) > 3
)
order by 1, 2 desc

这两个版本的关系表示不同 - 第一个返回一行(按组的性质),需要连接回原始表以显示所有记录,第二个直接从原始表中显示所有数据和立即联系。

您可以找到Demo at Sql Fiddle

答案 1 :(得分:2)

我认为你在寻找的东西可以在这里找到:

http://www.sql-ex.ru/help/select16.php

基本上,最好的解决方案是使用RANK功能。以下是该网站的示例代码:

SELECT maker, model, type FROM
(
SELECT maker, model, type, RANK() OVER(PARTITION BY type ORDER BY model) num
FROM Product
) X
WHERE num <= 3

您只需要修改“分区依据”部分,按照您的分数降序排序。

修改

根据您将使用MySQL的信息,您需要对上述查询(适用于Microsoft SQL)进行一些修改。您需要使用自己的RANK实现替换RANK函数。这并不难。完整的说明可以在这里找到:

http://thinkdiff.net/mysql/how-to-get-rank-using-mysql-query/

这会告诉你如何实现一个可以给你排名的计数器。

答案 2 :(得分:2)

SQL服务器中的

select p.player, p.score
from PS p
where p.score in (select top 3 score from PS 
                 where player = p.player order by score desc)
order by p.player asc, p.score desc
MySql中的

select p.player, p.score
    from PS p
    where p.score in (select score from PS 
                     where player = p.player order by score desc limit 3)
    order by p.player asc, p.score desc

答案 3 :(得分:1)

根据您使用的DBMS,您可以使用某种形式的row_number

在SQL Server 2008中,您可以使用

create table #player
( Player char, Score int )

insert into #player (Player, Score) Values
('A',5),('B',4),('A',3),('B',2),('A',1),('B',1),('A',2),('B',3),('A',4),('B',5)

select * from #player

select Player, Score from 
(
  select *, ROW_NUMBER() over(partition by Player order by Score desc) as rowNo 
  from #player
) as tmp
where tmp.rowNo <= 3

drop table #player