如何在MySQL中实现基于分数优先、击杀数次之的玩家唯一排名?
解决MySQL中玩家唯一排名的问题
你的问题核心在于原来的排名逻辑只依赖了分数这一个维度,FIND_IN_SET(score, ...)会把所有相同分数的玩家归为同一个排名,完全忽略了击杀数的优先级。要实现分数降序优先、击杀数降序次之的唯一排名,我们可以用两种方案,取决于你的MySQL版本:
方案1:MySQL 8.0+(推荐,语法简洁)
从MySQL 8.0开始支持窗口函数,ROW_NUMBER()可以完美生成唯一排名,它会按照你指定的排序规则为每一行分配一个唯一的序号:
SELECT ROW_NUMBER() OVER(ORDER BY T1.score DESC, T1.kills DESC) AS rank, T1.name, T1.score, T1.kills, T1.deaths, T2.credits, T1.connected FROM rankme T1 LEFT JOIN store_players T2 ON T1.name = T2.name ORDER BY T1.score DESC, T1.kills DESC;
为什么这个方案有效?
ROW_NUMBER()窗口函数会严格按照ORDER BY score DESC, kills DESC的顺序遍历每一行,即使分数相同,只要击杀数不同,就会分配不同的排名,完全满足你要的唯一排名需求。
方案2:MySQL 5.7及以下版本(无窗口函数时使用)
如果你的MySQL版本不支持窗口函数,可以用用户变量来实现排名逻辑,需要先按正确的顺序排序,再逐行累加排名:
SELECT @rank := @rank + 1 AS rank, temp.name, temp.score, temp.kills, temp.deaths, temp.credits, temp.connected FROM ( SELECT T1.name, T1.score, T1.kills, T1.deaths, T2.credits, T1.connected FROM rankme T1 LEFT JOIN store_players T2 ON T1.name = T2.name ORDER BY T1.score DESC, T1.kills DESC ) AS temp, (SELECT @rank := 0) AS init;
这个方案的逻辑:
- 子查询
temp先把所有玩家按分数降序、击杀数降序排好序; - 初始化变量
@rank为0,然后在遍历排序后的结果时,每一行都让@rank自增1,这样就得到了唯一的排名。
为什么你原来的方法失效?
你之前尝试添加ORDER BY T1.score, T1.kills只是调整了结果的显示顺序,但FIND_IN_SET(score, GROUP_CONCAT(score ORDER BY score DESC))的逻辑还是只看分数——它把所有相同分数的玩家都映射到同一个排名值,击杀数的排序不会影响这个分组结果,所以排名依然重复。
内容的提问来源于stack exchange,提问作者DM-98
相关产品推荐
相关产品推荐

