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

使用PL/SQL游标计算学生加权平均分并更新ETUDIANT表RANGE列

实现方案

1. 先计算加权平均分并生成符合要求的排名

先通过SQL关联三张表算出每个学生的加权平均分,再用RANK()窗口函数生成排名——这个函数会让相同分数的学生共享同一排名,且后续排名自动跳过重复名次(比如两个第1名之后,下一个直接是第3名):

WITH student_avg AS (
    SELECT 
        n.id_etudiant,
        SUM(n.note * m.coefficient) / SUM(m.coefficient) AS weighted_avg
    FROM NOTES n
    JOIN MODULE m ON n.id_module = m.id_module
    GROUP BY n.id_etudiant
),
student_rank AS (
    SELECT 
        id_etudiant,
        weighted_avg,
        RANK() OVER (ORDER BY weighted_avg DESC) AS student_range
    FROM student_avg
)
SELECT * FROM student_rank;

如果需要连续排名(相同分数同排名,后续名次不跳过),把RANK()换成DENSE_RANK()即可。

2. 用PL/SQL游标实现更新

以下是用游标遍历计算结果、更新ETUDIANT表RANGE列的代码,注释已经标清关键步骤:

DECLARE
    -- 定义游标,包含学生ID和对应排名
    CURSOR c_student_rank IS
        WITH student_avg AS (
            SELECT 
                n.id_etudiant,
                SUM(n.note * m.coefficient) / SUM(m.coefficient) AS weighted_avg
            FROM NOTES n
            JOIN MODULE m ON n.id_module = m.id_module
            GROUP BY n.id_etudiant
        ),
        student_rank AS (
            SELECT 
                id_etudiant,
                RANK() OVER (ORDER BY weighted_avg DESC) AS student_range
            FROM student_avg
        )
        SELECT id_etudiant, student_range FROM student_rank;
        
    -- 声明与表字段匹配的变量,避免类型不兼容
    v_id_etudiant ETUDIANT.id_etudiant%TYPE;
    v_range ETUDIANT.RANGE%TYPE;
BEGIN
    -- 可选:清空原有排名,确保新数据准确
    UPDATE ETUDIANT SET RANGE = NULL;
    
    -- 打开游标并遍历
    OPEN c_student_rank;
    LOOP
        FETCH c_student_rank INTO v_id_etudiant, v_range;
        -- 遍历结束时退出循环
        EXIT WHEN c_student_rank%NOTFOUND;
        
        -- 更新当前学生的排名
        UPDATE ETUDIANT
        SET RANGE = v_range
        WHERE id_etudiant = v_id_etudiant;
    END LOOP;
    CLOSE c_student_rank;
    
    -- 提交更新
    COMMIT;
EXCEPTION
    -- 异常处理:更新失败时回滚并输出错误信息
    WHEN OTHERS THEN
        ROLLBACK;
        DBMS_OUTPUT.PUT_LINE('更新失败:' || SQLERRM);
END;
/

3. 优化方案:批量更新(可选)

如果学生数据量较大,游标逐行更新效率偏低,可以改用MERGE语句批量更新,不用写PL/SQL游标也能实现需求:

MERGE INTO ETUDIANT e
USING (
    WITH student_avg AS (
        SELECT 
            n.id_etudiant,
            SUM(n.note * m.coefficient) / SUM(m.coefficient) AS weighted_avg
        FROM NOTES n
        JOIN MODULE m ON n.id_module = m.id_module
        GROUP BY n.id_etudiant
    ),
    student_rank AS (
        SELECT 
            id_etudiant,
            RANK() OVER (ORDER BY weighted_avg DESC) AS student_range
        FROM student_avg
    )
    SELECT id_etudiant, student_range FROM student_rank
) sr
ON (e.id_etudiant = sr.id_etudiant)
WHEN MATCHED THEN
    UPDATE SET e.RANGE = sr.student_range;
COMMIT;

内容的提问来源于stack exchange,提问作者Seffih Oualid Redouan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 11:55:20