如何获得关系的平均值,然后在 Laravel 7.x 中对其进行排序?
Posted
技术标签:
【中文标题】如何获得关系的平均值,然后在 Laravel 7.x 中对其进行排序?【英文标题】:How can I get the average of a relationship and then orderBy it in Laravel 7.x? 【发布时间】:2020-07-11 10:52:48 【问题描述】:我有一个名为 students
的表和一个名为 scores
的表。
students
表的主键是id
。
表scores
有一个外键student_id
到students.id
表scores
也有很多字段,其中两个是score
和year
,分别表示score的值和学生是哪一年得到这个分数的。
在一年中,一个学生获得了很多分数。我想得到他们的平均分数,并对学生在特定年份的平均分数进行排名。
模型“学生”有关系:
class Student extends Model
public function scores()
return $this->hasMany('App\Score');
我试过了: 在学生模型中,
class Student extends Model
public function average_score()
return $this->scores()
->selectRaw('avg(score) as score, student_id')
->groupBy('student_id');
在 StudentCtrl 中,
// Select only the student’s scores in a specific year
$yearQuery = function($query) use ($request)
return $query->where('year', '=', $request->year);
;
$list = Student::select('id', 'name')
->with(['average_score' => $yearQuery])
->orderBy('average_score') // <-- If I delete this it works
->paginate(15);
它失败了:SQLSTATE[42S22]:找不到列:1054 'order 子句'中的未知列 'average_score'
【问题讨论】:
如果是我,我会从原始 sql 开始 尝试使用 ->having() 而不是 ->with()with
生成在第一个 SQL 查询之后执行的第二个 SQL 查询。您不能根据第二个结果对第一个进行排序。我建议加入
也许这会有所帮助:***.com/a/62816609/7908390 你必须为这种 orderBy 子查询或加入它。
【参考方案1】:
在这里,我们将利用map()、groupBy()、avg()、sortBy()
$response = []; // we'll store our final response here
$students = Student::select('id', 'name')->with('scores')->limit(15)->get();
$students->map(function ($student)
// groupBy student's each score by year
return $student->scores->groupBy('year')->map(function ($score, $year) use ($student)
// create new array for simplicity
$score = [
'student_id' => $student->id,
'student_name' => $student->name,
'average_score' => $score->avg('score'),
'year' => $year,
];
return $score;
)->toArray();
)->map(function($lists) use(&$response)
// groupBy students with each year
collect($lists)->each(function($list) use(&$response)
$response[$list['year']][] = collect($list)->forget('year')->toArray();
);
)->toArray();
dd(collect($response)->map(function($list)
return collect($list)->sortBy('average_score')->all(); // you sort here
)->all());
样本响应
array:3 [
2016 => array:2 [
1 => array:3 [
"student_id" => 2
"student_name" => "Adam"
"average_score" => 30
]
0 => array:3 [
"student_id" => 1
"student_name" => "John"
"average_score" => 37.5
]
]
2017 => array:3 [
1 => array:3 [
"student_id" => 2
"student_name" => "Adam"
"average_score" => 50
]
0 => array:3 [
"student_id" => 1
"student_name" => "John"
"average_score" => 70
]
2 => array:3 [
"student_id" => 3
"student_name" => "Tony"
"average_score" => 80
]
]
2018 => array:1 [
0 => array:3 [
"student_id" => 3
"student_name" => "Tony"
"average_score" => 100
]
]
]
让我在下面的 cmets 中发布消息。干杯!
【讨论】:
哇,这真的很优雅,谢谢!但我最终还是使用了 SQL 语句,因为它要短得多……以上是关于如何获得关系的平均值,然后在 Laravel 7.x 中对其进行排序?的主要内容,如果未能解决你的问题,请参考以下文章