如何获得关系的平均值,然后在 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_idstudents.idscores也有很多字段,其中两个是scoreyear,分别表示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 中对其进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Laravel/Eloquent 中获得完整的关系

如何在laravel中获得多态关系?

我如何获得 Laravel 与其关系值的关系?

我如何获得 Laravel 与其关系值的关系?

Laravel Eloquent 如何根据计数获得关系总和

Laravel Eloquent - 如何获得嵌套关系