3

假设我有一张这样的桌子:

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

4 回答 4

3

这是每组产生前 n 个的老式(阅读:基本 sql)方式。您可以在分组条件下(这里是玩家)将表格加入到自身中,并在右侧选择得分较高的记录;如果有三个或更少这样的记录,则该行是每组前 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

这两个版本在关系的表示上有所不同 - 第一个返回一行(按 group by 的性质)并且需要连接回原始表以显示所有记录,第二个版本直接从原始表中工作,一次显示所有数据和关系.

你可以在 Sql Fiddle找到Demo 。

于 2012-04-23T22:24:07.823 回答
3

在 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
于 2012-04-23T23:18:12.610 回答
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

您只需要修改 Partition By 部分以按分数降序排列。

编辑

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

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

这将向您展示如何实现一个可以为您提供排名编号的计数器。

于 2012-04-23T20:11:03.897 回答
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
于 2012-04-23T20:09:56.687 回答