You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 8通过三个关联模型统计各学年去重学生人数问题

实现方案

1 先确认模型关联配置

Student和Group为多对多关系(一个学生可加入多个群组,一个群组包含多个学生),如果还没配置正确关联,先调整模型代码:

  • Student模型中群组关联调整为:
public function groups()
{
    return $this->belongsToMany(Group::class);
}
  • Group模型中学生关联保持多对多即可,Major和Student的一对多关联无需调整。

2 编写统计逻辑(SQL层实现,性能最优)

推荐直接用查询构建器在SQL层完成统计,避免查询全量数据后处理的性能损耗,适合生产环境使用。以下是Major控制器index方法的示例代码:

public function index()
{
    $majors = Major::query()
        ->select('majors.*')
        // 批量统计1-7学年的独立学生数
        ->when(true, function ($query) {
            for ($year = 1; $year <= 7; $year++) {
                $query->selectSub(
                    function ($subQuery) use ($year) {
                        $subQuery->from('students')
                            ->join('group_student', 'students.id', '=', 'group_student.student_id')
                            ->join('groups', 'group_student.group_id', '=', 'groups.id')
                            ->whereColumn('students.major_id', 'majors.id')
                            ->where('groups.course_year', $year)
                            ->count('DISTINCT students.id');
                    },
                    "year_{$year}_count"
                );
            }
        })
        ->get();

    return view('major.index', compact('majors'));
}

逻辑说明

  • 用DISTINCT students.id去重,确保同一个学生同一学年加入多个群组仅统计1次
  • 各学年统计独立,学生加入不同学年的群组会分别计入对应学年的人数,完全符合统计规则

3 视图层展示

在专业列表Blade模板中直接读取统计字段即可:

<table>
    <thead>
        <tr>
            <th>专业名称</th>
            @for($year = 1; $year <=7; $year++)
            <th>{{ $year }}学年人数</th>
            @endfor
        </tr>
    </thead>
    <tbody>
        @foreach($majors as $major)
        <tr>
            <td>{{ $major->name }}</td>
            @for($year = 1; $year <=7; $year++)
            <td>{{ $major->{"year_{$year}_count"} ?? 0 }}</td>
            @endfor
        </tr>
        @endforeach
    </tbody>
</table>

可选方案:集合处理(适合小数据量场景)

如果专业、学生总数据量小于1万,也可以用更直观的集合处理方式实现:

$majors = Major::query()
    ->with('students.groups')
    ->get()
    ->map(function ($major) {
        $yearCounts = array_fill(1, 7, 0);
        foreach ($major->students as $student) {
            // 拿到学生加入群组的所有学年,去重后计数
            $joinYears = $student->groups->pluck('course_year')->unique();
            foreach ($joinYears as $year) {
                isset($yearCounts[$year]) && $yearCounts[$year]++;
            }
        }
        $major->year_counts = $yearCounts;
        return $major;
    });

内容的提问来源于stack exchange,提问作者Ivan Slavchev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 17:06:05