PHP MySQL如何查询自身分数上下各2名的排行榜记录
实现游戏排行榜自身分数上下各2名的查询方案
这个需求完全可行,以下是具体实现方法:
一、MySQL 查询实现
假设你的排行榜表名为leaderboard,包含字段player_id(玩家唯一标识)、player_name(玩家名称)、score(分数),分数越高排名越靠前。
1. 核心思路
先计算出自身的排名,再筛选出排名在「自身排名-2」到「自身排名+2」之间的记录。需要注意同分场景的排名逻辑,这里提供两种常见排名方式:
方式1:严格排名(同分玩家占用不同排名)
-- 先获取自身排名 SELECT COUNT(*) + 1 AS my_rank FROM leaderboard WHERE score > (SELECT score FROM leaderboard WHERE player_id = '你的玩家ID'); -- 查询上下各2名的记录 WITH ranked_players AS ( SELECT player_name, score, RANK() OVER (ORDER BY score DESC) AS player_rank FROM leaderboard ) SELECT player_rank, player_name, score FROM ranked_players WHERE player_rank BETWEEN ( SELECT COUNT(*) + 1 FROM leaderboard WHERE score > (SELECT score FROM leaderboard WHERE player_id = '你的玩家ID') ) - 2 AND ( SELECT COUNT(*) + 1 FROM leaderboard WHERE score > (SELECT score FROM leaderboard WHERE player_id = '你的玩家ID') ) + 2 ORDER BY player_rank ASC;
方式2:稠密排名(同分玩家共享同一排名)
只需将上述代码中的RANK()替换为DENSE_RANK()即可,适合需要同分同排名的场景。
兼容低版本MySQL(<8.0,无窗口函数)
用变量计算排名:
-- 查询上下各2名的记录 SELECT player_rank, player_name, score FROM ( SELECT @rank := @rank + 1 AS player_rank, player_name, score FROM leaderboard, (SELECT @rank := 0) AS r ORDER BY score DESC ) AS ranked WHERE player_rank BETWEEN ( SELECT COUNT(*) + 1 FROM leaderboard WHERE score > (SELECT score FROM leaderboard WHERE player_id = '你的玩家ID') ) - 2 AND ( SELECT COUNT(*) + 1 FROM leaderboard WHERE score > (SELECT score FROM leaderboard WHERE player_id = '你的玩家ID') ) + 2;
二、PHP 代码处理
以下是基于PDO的实现示例,确保查询逻辑与数据库交互的完整性:
<?php // 数据库连接参数 $host = 'localhost'; $dbname = '你的数据库名'; $username = '你的数据库账号'; $password = '你的数据库密码'; try { // 初始化PDO连接 $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 当前玩家ID $playerId = '你的玩家ID'; // 获取自身排名 $rankStmt = $pdo->prepare(" SELECT COUNT(*) + 1 AS my_rank FROM leaderboard WHERE score > (SELECT score FROM leaderboard WHERE player_id = :playerId) "); $rankStmt->bindParam(':playerId', $playerId, PDO::PARAM_STR); $rankStmt->execute(); $myRank = $rankStmt->fetch(PDO::FETCH_ASSOC)['my_rank']; // 计算查询范围(避免排名小于1) $minRank = max(1, $myRank - 2); $maxRank = $myRank + 2; // 查询目标记录 $stmt = $pdo->prepare(" WITH ranked_players AS ( SELECT player_name, score, RANK() OVER (ORDER BY score DESC) AS player_rank FROM leaderboard ) SELECT player_rank, player_name, score FROM ranked_players WHERE player_rank BETWEEN :minRank AND :maxRank ORDER BY player_rank ASC "); $stmt->bindParam(':minRank', $minRank, PDO::PARAM_INT); $stmt->bindParam(':maxRank', $maxRank, PDO::PARAM_INT); $stmt->execute(); // 输出结果 $results = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($results as $row) { echo "{$row['player_rank']}. {$row['player_name']} {$row['score']}\n"; } } catch(PDOException $e) { echo "数据库错误:" . $e->getMessage(); } $pdo = null; ?>
关键注意点
- 当自身排名为前2名时,
minRank会被强制设为1,避免出现无效的负排名; - 若自身排名为倒数2名,
maxRank会自动匹配表中最大排名,不会返回空结果; - 根据业务需求选择合适的排名算法(严格/稠密),确保排行榜逻辑符合预期。
内容的提问来源于stack exchange,提问作者Rachan Neamprasert
相关产品推荐
相关产品推荐

