我在数据透视表 table 中有一个值 'marks',如何使用查询生成器根据 'marks' 值查找学生排名?

I have a value 'marks' in a pivot table, how to find student rank based on 'marks' value using query builder?

我有两个模型 Exam 和 Student,在每个学生尝试 Exam 之后,her/him 获得的分数存储在 pivot table exam_user 中。我需要根据获得的分数对学生进行排名。

现在我正在为此使用一个非常低效的解决方案,它涉及一个 for 循环。下面是实现

            $rank=0;
            $attempts = DB::table('exam_user')
                    ->where('exam_id',$exam->id)
                    ->orderBy('marks','desc')
                    ->get();
            foreach ($attempts as $attempt) {
                $rank++;
                if($attempt->user_id==Auth::id())
                    break;
            }

有没有什么方法可以在不使用 for 循环的情况下确定排名,只需使用 laravel 中的查询生成器。我想我在这里缺少一些 SQL 基础知识。

排名就是比你值大的人数+1。

因此你可以这样做:

$userMarks = DB::table('exam_user')
    ->select('marks')
    ->where('exam_id', $exam->id)
    ->where('user_id', '=', Auth::id())
    ->firstOrFail()
    ->marks;

$rank = DB::table('exam_user')
    ->where('exam_id', $exam->id)
    ->where('marks', '>', $userMarks)
    ->count() + 1;

您也可以将其放入一个查询中:

$userId = Auth::id();
$rank = DB::table('exam_user')
            ->where('exam_id', $exam->id)
            ->whereRaw(
                "marks > (select eu2.marks from exam_user eu2 where eu2.exam_id = {$exam->id} and eu2.user_id = {$userId}) limit 1"
            )
            ->count() + 1;

您也可以考虑让您将 table exam_user 作为一个实际模型,并将其称为 Marks,因为它包含您想要查询的重要数据。

然后您可以将以下内容添加到 Exam 模型中:

Class Exam {
    // ...
    public function marks() {
        $this->hasMany(Marks::class);
    }    
    // ...
}

这意味着您可以这样做:

$userId = Auth::id();
$rank = $exam->marks()
            ->whereRaw(
                "marks > (select marks from exam_user where exam_id = {$exam->id} and user_id = {$userId}) limit 1"
            )
            ->count() + 1;