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

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;
});

验证结果

两种方法最终都会得到你期望的结果:

idfirstNamelastNametotal_scorerank
19CatRat801
33RoseJack802
43StuartLittle733

内容的提问来源于stack exchange,提问作者Oops

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 20:07:38