Laravel如何按学校ID统计特定数据?
Laravel按学校ID统计时段数据的正确实现
我来帮你梳理下这个统计需求的正确实现方式~首先得指出你当前代码里的小问题:
- 你现在的
$morning_session和$afternoon_session调用count()后,返回的是有多少个学校存在对应时段的学生,而不是每个学校各自的学生数量。 - 多次分开查询数据库,效率偏低,我们可以合并成一次查询搞定。
下面给你几种实用的解决方案,按需选择:
方案一:一次Query Builder查询搞定双时段统计(推荐)
用CASE WHEN语法在一次查询中同时统计两个时段的学生数,还能通过左连接确保没有对应时段学生的学校也会被统计(数量为0):
$schoolSessionStats = DB::table('sekolah') ->leftJoin('pelajar', 'sekolah.sekolah_id', '=', 'pelajar.sekolah_id') ->select( 'sekolah.sekolah_id', 'sekolah.nama_sekolah', // 替换成你学校表的名称字段,不需要可以删掉 DB::raw('COUNT(CASE WHEN pelajar.pelajar_sesi = "Morning" THEN 1 END) as morning_count'), DB::raw('COUNT(CASE WHEN pelajar.pelajar_sesi = "Afternoon" THEN 1 END) as afternoon_count') ) ->groupBy('sekolah.sekolah_id', 'sekolah.nama_sekolah') // 分组字段要和select里的非聚合字段对应 ->get();
拿到结果后,每个元素都会包含sekolah_id、morning_count和afternoon_count,直接遍历使用即可。
方案二:使用Eloquent关联统计(如果有模型的话)
如果你已经定义了Sekolah和Pelajar模型,用Eloquent的withCount方法会更简洁,代码可读性更高:
首先在Sekolah模型里定义关联:
// app/Models/Sekolah.php public function pelajar() { return $this->hasMany(Pelajar::class, 'sekolah_id'); }
然后执行统计查询:
$schools = Sekolah::withCount([ 'pelajar as morning_count' => function ($query) { $query->where('pelajar_sesi', 'Morning'); }, 'pelajar as afternoon_count' => function ($query) { $query->where('pelajar_sesi', 'Afternoon'); } ])->get();
这样每个Sekolah实例都会带上morning_count和afternoon_count两个属性,直接调用就行。
方案三:循环查询(不推荐,仅小数据量可用)
如果你的学校数量很少,也可以先获取所有学校,再逐个查询对应时段的学生数,但这种方法会产生N+1查询问题(N是学校数量),数据量大时性能很差:
$schools = DB::table('sekolah')->get(); foreach ($schools as $school) { $school->morning_count = DB::table('pelajar') ->where('sekolah_id', $school->sekolah_id) ->where('pelajar_sesi', 'Morning') ->count(); $school->afternoon_count = DB::table('pelajar') ->where('sekolah_id', $school->sekolah_id) ->where('pelajar_sesi', 'Afternoon') ->count(); }
总结
优先选择方案一或方案二,它们只需要一次数据库查询,性能更优,代码也更简洁。如果项目用了Eloquent模型,方案二是最贴合Laravel风格的写法。
内容的提问来源于stack exchange,提问作者MrlinY
相关产品推荐
相关产品推荐

