如何获取mysqli多查询结果及用户在排行榜的排名位置
问题分析与解决方案
你的代码主要存在两个核心问题:
multi_query与预处理参数绑定不兼容:multi_query执行后返回的是布尔值(仅表示查询是否启动成功),而非mysqli预处理语句对象,因此后续调用bind_param必然报错。- SQL语句语法错误:代码末尾多了冗余的
";"",导致查询解析失败。
下面给出两种正确的实现方式,优先推荐第一种(安全且简洁):
方案一:单查询+预处理参数绑定(推荐)
将排名变量的初始化逻辑合并到主查询中,通过CROSS JOIN初始化变量,这样可以用预处理语句安全绑定参数,彻底避免SQL注入风险:
// 构造单查询SQL,内部完成排名变量初始化 $sql = "SELECT RANK FROM ( SELECT @rank:=@rank+1 AS 'RANK', user_id FROM ( SELECT score, user_id FROM `fishing_contest` GROUP BY user_id ORDER BY score DESC ) as t1 CROSS JOIN (SELECT @rank:=0) AS init_rank ) as t2 WHERE user_id = ?"; // 初始化预处理语句 $stmt = $mysqli->prepare($sql); // 绑定用户ID参数(i表示整数类型) $stmt->bind_param("i", $_SESSION['id']); // 执行查询 $stmt->execute(); // 获取结果集 $data = $stmt->get_result(); // 提取用户排名数据 $userContest = $data->fetch_assoc(); // 结果使用示例 if ($userContest) { echo "当前排名:" . $userContest['RANK']; } else { echo "未查询到你的参赛记录"; }
方案二:使用multi_query(不推荐,存在注入风险)
如果一定要用多查询方式,需要跳过第一个SET语句的结果,且无法使用参数绑定(需手动确保用户ID的安全性):
// 强制转换用户ID为整数,避免SQL注入风险 $safeUserId = (int)$_SESSION['id']; // 构造多查询SQL $sql = "SET @rank=0; SELECT RANK FROM ( SELECT @rank:=@rank+1 AS 'RANK', user_id FROM ( SELECT score, user_id FROM `fishing_contest` GROUP BY user_id ORDER BY score DESC ) as t1 ) as t2 WHERE user_id = $safeUserId"; // 执行多查询 if ($mysqli->multi_query($sql)) { // 跳过第一个SET语句的结果集 $mysqli->next_result(); // 获取第二个查询的结果 if ($result = $mysqli->store_result()) { $userContest = $result->fetch_assoc(); $result->free(); } } // 结果使用示例 if ($userContest) { echo "当前排名:" . $userContest['RANK']; } else { echo "未查询到你的参赛记录"; }
关键说明
- 预处理语句(
prepare/bind_param)仅支持单查询,无法与multi_query配合使用。 - 方案一的
CROSS JOIN初始化变量方式,是MySQL中实现排名查询的标准写法,既安全又高效。
内容的提问来源于stack exchange,提问作者MilKMiracle
相关产品推荐
相关产品推荐

