如何筛选player_ratings表最高评分行,去重保留首行?
解决玩家最高评分去重问题
嘿,我明白你遇到的困扰了——你的查询确实能揪出每个玩家的最高评分,但当同一个玩家有好几条相同最高评分的记录时,所有匹配行都会被返回,没法只保留表中最上方的那一行。咱们调整下查询逻辑,轻松搞定这个问题!
问题根源
你原来用GROUP BY+JOIN的方式,先拿到每个玩家的最高评分,再关联回原表,这样所有等于最高评分的行都会被拉出来,自然会出现重复的玩家记录。要解决这个,我们得给每个玩家的评分记录排个序,只保留每组的第一条。
最优解决方案:使用窗口函数(推荐)
现在主流数据库(MySQL 8.0+、PostgreSQL、SQL Server等)都支持窗口函数,用ROW_NUMBER()就能精准实现需求:
SELECT player_id, rating FROM ( SELECT player_id, rating, -- 按玩家分组,评分降序排序,给每行分配唯一编号 ROW_NUMBER() OVER ( PARTITION BY player_id ORDER BY rating DESC -- 如果你表中有主键、创建时间这类能明确行顺序的列,比如`id`,可以加上它确保排序稳定: -- ORDER BY rating DESC, id ASC ) AS row_num FROM player_ratings ) ranked_ratings -- 只保留每组的第一行 WHERE row_num = 1 ORDER BY rating DESC;
这个查询的逻辑很清晰:
- 内层子查询给每个玩家的所有评分记录按评分降序分配编号,评分相同的记录会按数据库默认行顺序(或你指定的列)分配不同编号;
- 外层查询只筛选编号为1的行,这样每个玩家只会保留最高评分的第一条记录,完美解决重复问题。
兼容旧版本数据库的方案(比如MySQL 5.7及以下)
如果你的数据库不支持窗口函数,可以用关联子查询的方式替代:
SELECT pr.player_id, pr.rating FROM player_ratings pr WHERE NOT EXISTS ( SELECT 1 FROM player_ratings pr2 WHERE pr2.player_id = pr.player_id AND ( -- 排除存在更高评分,或评分相同但排在更前面的记录 pr2.rating > pr.rating OR (pr2.rating = pr.rating AND pr2.player_id < pr.player_id) ) ) ORDER BY pr.rating DESC;
不过这种写法的可读性和效率都不如窗口函数,优先推荐第一种方案。
最终效果
运行上面的查询后,就能得到你期望的结果:
| player_id | rating |
|---|---|
| 1 | 950 |
| 2 | 850 |
内容的提问来源于stack exchange,提问作者leadingSkill
相关产品推荐
相关产品推荐

