Laravel+MySQL:基于用户周最高得分按姓名升序生成排名
解决Laravel中用户周度高分排名问题
我明白你的需求啦——你已经能拿到本周用户的最高得分列表,但需要给这些用户生成按firstName升序排列的连续排名(相同分数的用户排名依次递增,而非并列)。下面给你两种靠谱的解决方案:
方法一:直接在SQL中使用窗口函数(推荐)
如果你的MySQL版本是8.0及以上,直接用ROW_NUMBER()窗口函数就能一步到位生成排名。我们先通过子查询得到每个用户的周最高得分,再对这个结果集按total_score降序、firstName升序来生成排名:
$users = DB::table(function ($query) use ($start_date) { // 子查询:获取每个用户的周最高得分 $query->select('users.id', 'users.firstName', 'users.lastName', DB::raw('MAX(game_scores.score) as total_score')) ->join('game_scores', 'users.id', '=', 'game_scores.user_id') ->whereBetween('game_scores.created_at', [$start_date, date('Y-m-d H:i:s')]) ->groupBy('users.id', 'users.firstName', 'users.lastName'); }, 'user_scores') ->select('id', 'firstName', 'lastName', 'total_score', DB::raw('ROW_NUMBER() OVER (ORDER BY total_score DESC, firstName ASC) as `rank`')) ->get();
这里用ROW_NUMBER()而不是RANK()/DENSE_RANK(),是因为你期望相同分数的用户(比如Cat和Rose)排名是1和2,而非并列第1。如果之后需要并列排名,再换成RANK()即可。
方法二:Laravel集合层面处理排名
如果你的MySQL版本较低不支持窗口函数,可以在拿到查询结果后,通过Laravel集合的遍历方法添加排名字段:
// 先执行你原来的查询,补充firstName排序 $users = DB::table('users') ->join('game_scores', 'users.id', '=', 'game_scores.user_id') ->select('users.id', 'users.firstName', 'users.lastName', DB::raw('MAX(game_scores.score) as total_score')) ->whereBetween('game_scores.created_at',[$start_date, date('Y-m-d H:i:s')]) ->groupBy('users.id', 'users.firstName', 'users.lastName') ->orderBy('total_score', 'desc') ->orderBy('firstName', 'asc') // 必须补充这个排序,确保符合你的要求 ->get(); // 给集合中的每个元素添加rank字段 $rankedUsers = $users->map(function ($user, $index) { $user->rank = $index + 1; // 集合索引从0开始,加1得到自然排名 return $user; });
验证结果
两种方法最终都会得到你期望的结果:
| id | firstName | lastName | total_score | rank |
|---|---|---|---|---|
| 19 | Cat | Rat | 80 | 1 |
| 33 | Rose | Jack | 80 | 2 |
| 43 | Stuart | Little | 73 | 3 |
内容的提问来源于stack exchange,提问作者Oops
相关产品推荐
相关产品推荐

