You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用ROW_NUMBER、RANK或DENSE_RANK实现同分玩家共享名次的玩家积分榜(含位次跳过规则)

如何使用ROW_NUMBER、RANK或DENSE_RANK实现同分玩家共享名次的玩家积分榜(含位次跳过规则)

嘿,这个需求我太熟了!正好可以用SQL里的窗口函数来解决,尤其是RANK()完全匹配你要的位次规则——同分玩家共享名次,且下一个位次会跳过中间的数字(比如两个第1之后直接到第3)。我来给你一步步拆解实现方法:

第一步:先确认数据结构

你已经给出了玩家表和成绩表的创建及插入语句,我帮你格式化好:

CREATE TABLE players (
    id INT PRIMARY KEY,
    name VARCHAR(50)
);

CREATE TABLE results (
    id INT PRIMARY KEY,
    player_id INT,
    score INT,
    FOREIGN KEY (player_id) REFERENCES players(id)
);

INSERT INTO players (id,name) VALUES 
(1, 'Uolevi'),
(2,'Maija'),
(3,'Liisa'),
(4,'Kaaleppi'),
(5,'Kotivalo');

INSERT INTO results (id, player_id, score) VALUES 
(1, 1, 100), 
(2, 2, 200), 
(3, 3, 200), 
(4, 4, 100), 
(5, 5, 50);

第二步:实现符合要求的查询语句

直接用RANK()窗口函数就能搞定,同时要注意同分玩家按姓名字母顺序排列,完整查询如下:

SELECT
    RANK() OVER (ORDER BY r.score DESC, p.name ASC) AS "Order",
    p.name AS "Name",
    r.score AS "Score"
FROM players p
JOIN results r ON p.id = r.player_id
ORDER BY "Order", "Name";

第三步:解释关键逻辑

  • RANK() OVER (ORDER BY r.score DESC, p.name ASC):这是核心!这个窗口函数会先按分数从高到低排序,分数相同的情况下按姓名升序排列。同分的玩家会获得相同的位次,而且会自动跳过中间的数字——比如有2个玩家是第1名,下一个玩家直接是第3名,完全符合你的要求。
  • JOIN关联表:通过player_id把玩家表和成绩表关联起来,这样就能同时获取玩家姓名和对应的分数。
  • 最终排序:最后的ORDER BY "Order", "Name"确保结果按位次和姓名顺序输出,和你预期的格式完全一致。

对比三个常用窗口函数的区别(帮你理清为什么选RANK)

为了让你更清楚,我顺便对比一下另外两个常用的排名窗口函数:

  • ROW_NUMBER():不管分数是否相同,都会给每一行分配唯一的连续位次。比如两个200分的玩家会被标记为1和2,不符合你共享名次的需求。
  • RANK():就是我们用的这个,同分共享位次,且跳过中间的数字,完美匹配你的规则。
  • DENSE_RANK():同分共享位次,但下一个位次是连续的(比如两个1之后是2),不符合你要跳过位次的要求。

查询结果(和你预期完全一致)

OrderNameScore
1Liisa200
1Maija200
3Kaaleppi100
3Uolevi100
5Kotivalo50

备注:内容来源于stack exchange,提问作者FC Chelsea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 07:13:03