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

Laravel列访问器sum()求和实现用户得分排行榜遇阻

嘿,我来帮你搞定这个Laravel用户得分排行榜的问题!你的表结构逻辑很清晰,核心就是要统计每个用户所有成功挑战的得分总和对吧?咱们一步步来解决:

第一步:先确保模型关联正确

首先在User模型里定义和Answer的关联关系,让Eloquent能正确关联用户的挑战记录:

// app/Models/User.php
public function answers()
{
    return $this->hasMany(Answer::class);
}

第二步:用「访问器」实现单用户总得分

如果你只是想在单个用户实例里获取总得分,列访问器确实好用,直接在User模型里添加这个访问器:

public function getTotalScoreAttribute()
{
    // 只统计成功挑战的得分,默认如果没有得分返回0
    return $this->answers()->where('success', true)->sum('score') ?? 0;
}

之后你就可以直接通过$user->total_score拿到这个用户的总得分啦~

第三步:高效制作排行榜(重点!避免N+1查询)

但如果是做排行榜,直接用上面的访问器会有N+1查询问题(每查一个用户就单独查一次得分),这时候用Laravel的withSum方法来预加载统计数据才是最优解:

$leaderboard = User::withSum(
    // 给统计结果起别名total_score,只统计成功的挑战
    ['answers as total_score' => function ($query) {
        $query->where('success', true);
    }], 
    'score' // 要求和的字段是answers表的score
)
->selectRaw('users.*, COALESCE(total_score, 0) as total_score') // 把null得分转成0
->orderByDesc('total_score') // 按总得分降序排列
->get(['id', 'name', 'mail']); // 只取需要的字段,提升性能

这样执行完,$leaderboard里的每个用户对象都自带total_score字段,而且全程只需要2次数据库查询,非常高效!

备选方案:用DB门面直接写原生查询

如果你更喜欢用原生SQL风格,也可以这么写:

$leaderboard = DB::table('users')
    ->leftJoin('answers', 'users.id', '=', 'answers.user_id')
    ->where('answers.success', true)
    ->select(
        'users.id', 
        'users.name', 
        'users.mail', 
        DB::raw('COALESCE(SUM(answers.score), 0) as total_score')
    )
    ->groupBy('users.id', 'users.name', 'users.mail')
    ->orderByDesc('total_score')
    ->get();

这样不管是用Eloquent还是原生查询,都能轻松实现你要的排行榜功能啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:24:23