我有两个模型Exam和Student,每个学生尝试一次将由他/他获得的标记存储在数据透视表test_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基础知识。
答案 0 :(得分:0)
排名是拥有比您的价值+ 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;
您还可以考虑将数据透视表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;