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

如何用最少PHP代码结合WHERE条件实现多科目考试成绩批量统计?

优化学校成绩统计的PHP代码方案

你当前的问题核心是重复代码过多——每个考试、每个性别分组都要写几乎一样的查询逻辑。用数组+循环或者更高效的SQL聚合查询可以彻底解决这个问题,下面给你两种实用方案:

方案1:用数组定义维度,循环生成查询(易理解,适合小规模场景)

先把需要统计的所有维度(考试场次、性别分组)用数组定义,然后通过循环批量处理,避免重复写SQL。同时记得用预处理语句防止SQL注入(你原来的直接拼接变量存在安全风险)。

代码示例:

// 1. 定义需要统计的维度数组
// 假设你的考试字段是chem1_1到chem1_8(chem1的8次考试)、chem2_1到chem2_8(chem2的8次考试)
$exam_fields = [
    'chem1_1' => '化学1-第1次',
    'chem1_2' => '化学1-第2次',
    // ... 补全到chem1_8
    'chem2_1' => '化学2-第1次',
    // ... 补全到chem2_8
];
// 性别分组:键是数据库中的sex值,值是显示用的名称
$gender_groups = [
    'M' => '男生',
    'F' => '女生',
    'all' => '全体'
];

// 2. 循环处理每个维度,批量统计
$stats = [];
foreach ($exam_fields as $field => $exam_name) {
    foreach ($gender_groups as $sex_val => $gender_name) {
        // 构建WHERE条件:全体用户不需要sex筛选
        $where_sex = ($sex_val === 'all') ? '' : "AND sex = ?";
        // 预处理SQL:统计及格人数(假设及格线60)、总人数、平均分
        $sql = "
            SELECT 
                COUNT(*) AS total_students,
                COUNT(CASE WHEN $field >= 60 THEN 1 END) AS pass_students,
                AVG($field) AS avg_score
            FROM test_2324 
            WHERE cls = ? AND section = ? $where_sex
        ";
        // 初始化预处理语句
        $stmt = mysqli_prepare($db, $sql);
        // 绑定参数:根据是否是全体,绑定不同数量的参数
        if ($sex_val === 'all') {
            mysqli_stmt_bind_param($stmt, "ss", $cls_show, $sect_show);
        } else {
            mysqli_stmt_bind_param($stmt, "sss", $cls_show, $sect_show, $sex_val);
        }
        // 执行查询
        mysqli_stmt_execute($stmt);
        // 获取结果
        $result = mysqli_stmt_get_result($stmt);
        $row = mysqli_fetch_assoc($result);
        
        // 计算及格率(避免除以0)
        $pass_rate = $row['total_students'] > 0 ? ($row['pass_students'] / $row['total_students']) * 100 : 0;
        
        // 存储统计结果
        $stats[$exam_name][$gender_name] = [
            'total' => $row['total_students'],
            'pass_count' => $row['pass_students'],
            'pass_rate' => round($pass_rate, 2) . '%',
            'avg_score' => round($row['avg_score'], 2)
        ];
        
        // 关闭语句
        mysqli_stmt_close($stmt);
    }
}

// 3. 输出统计结果(示例)
foreach ($stats as $exam => $gender_data) {
    echo "<h3>$exam</h3>";
    foreach ($gender_data as $gender => $data) {
        echo "<p>$gender:总人数{$data['total']},及格率{$data['pass_rate']},平均分{$data['avg_score']}</p>";
    }
}

方案2:用SQL聚合+GROUP BY一次性获取所有统计(更高效,减少数据库请求)

如果数据量较大,多次查询会影响性能,推荐用SQL的GROUP BY和WITH ROLLUP一次性统计所有性别分组(包括全体),同时计算多个考试场次的指标。

代码示例:

// 1. 定义需要统计的考试字段(和方案1一致)
$exam_fields = [
    'chem1_1', 'chem1_2', /* ... 补全到chem1_8 */
    'chem2_1', /* ... 补全到chem2_8 */
];

// 2. 动态构建SQL的统计字段
$select_clauses = [];
foreach ($exam_fields as $field) {
    $select_clauses[] = "COUNT(CASE WHEN $field >= 60 THEN 1 END) AS {$field}_pass";
    $select_clauses[] = "AVG($field) AS {$field}_avg";
}
$select_part = implode(', ', $select_clauses);

// 3. 构建完整SQL:用GROUP BY WITH ROLLUP自动生成全体统计
$sql = "
    SELECT 
        sex,
        COUNT(*) AS total_students,
        $select_part
    FROM test_2324 
    WHERE cls = ? AND section = ?
    GROUP BY sex WITH ROLLUP
";

// 4. 预处理执行
$stmt = mysqli_prepare($db, $sql);
mysqli_stmt_bind_param($stmt, "ss", $cls_show, $sect_show);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);

// 5. 解析结果
$stats = [];
while ($row = mysqli_fetch_assoc($result)) {
    // 判断当前行是男生、女生还是全体(ROLLUP生成的总行sex为NULL)
    $gender = match($row['sex']) {
        'M' => '男生',
        'F' => '女生',
        null => '全体'
    };
    $stats[$gender] = [
        'total' => $row['total_students']
    ];
    // 遍历每个考试字段,提取及格数、平均分并计算及格率
    foreach ($exam_fields as $field) {
        $pass_count = $row["{$field}_pass"];
        $avg_score = $row["{$field}_avg"];
        $pass_rate = $row['total_students'] > 0 ? ($pass_count / $row['total_students']) * 100 : 0;
        $stats[$gender][$field] = [
            'pass_count' => $pass_count,
            'pass_rate' => round($pass_rate, 2) . '%',
            'avg_score' => round($avg_score, 2)
        ];
    }
}

// 6. 输出结果(示例)
foreach ($stats as $gender => $data) {
    echo "<h3>$gender</h3>";
    echo "<p>总人数:{$data['total']}</p>";
    foreach ($exam_fields as $field) {
        echo "<p>$field:及格人数{$data[$field]['pass_count']},及格率{$data[$field]['pass_rate']},平均分{$data[$field]['avg_score']}</p>";
    }
}

关键注意事项

  • SQL注入防护:必须用预处理语句(mysqli_prepare)绑定参数,绝对不能直接把$cls_show、$sect_show这类用户输入拼接进SQL。
  • 空值处理:计算平均分、及格率时要判断总人数是否为0,避免出现除以0的错误。
  • 字段命名:如果你的考试字段命名规则不同(比如不是chemX_Y),只需要调整$exam_fields数组即可,不需要修改核心逻辑。

内容的提问来源于stack exchange,提问作者Goutham Tamil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 15:33:19