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

PL/SQL存储过程陷入无限循环,求排查及部门低薪员工实现方案

问题描述

现有一个7列的员工表emple,存储员工信息,已有大量数据且持续新增。需要编写PL/SQL存储过程,查询每个部门薪资最低的2名员工(支持新增部门),但当前编写的存储过程陷入无限循环,代码如下:

create or replace procedure lowemployees
as
cursor cur1 is select * from emple order by dept_no,salario;
empleadus emple%rowtype;
i number;
depcursor emple.dept_no%type;
depcompare emple.dept_no%type;
begin
i:=0;
open cur1;
fetch cur1 into empleadus;
depcursor:=empleadus.dept_no;
depcompare:=depcursor+1;
while cur1%found loop
while i<2 loop
dbms_output.put_line(empleadus.emp_no||'|'||empleadus.nombre||'|'||empleadus.oficio||'|'||empleadus.salario||'|'||empleadus.dept_no);
i:=i+1;
fetch cur1 into empleadus;
end loop;
depcursor:=empleadus.dept_no;
depcompare:=depcursor+1;
while depcursor<depcompare loop
fetch cur1 into empleadus;
i:=0;
depcursor:=empleadus.dept_no;
end loop;
dbms_output.put_line(empleadus.emp_no||'|'||empleadus.nombre||'|'||empleadus.oficio||'|'||empleadus.salario||'|'||empleadus.dept_no);
depcompare:=depcursor+1;
fetch cur1 into empleadus;
end loop;
close cur1;
end lowemployees;
问题分析

无限循环的核心原因是第二个while depcursor<depcompare逻辑完全错误:

  • depcompare被设为depcursor+1,只要当前部门编号不是最大值,depcursor<depcompare永远为真,会持续fetch直到游标耗尽,且外层循环未正确判断游标状态,导致逻辑混乱。
  • 外层循环在处理完每个部门后额外输出数据并重复fetch,逻辑冗余且破坏了游标遍历的连贯性。
解决方案

方案1:修复原存储过程逻辑

调整游标遍历逻辑,按部门分组取前2条薪资最低记录:

create or replace procedure lowemployees
as
    cursor cur1 is select * from emple order by dept_no, salario;
    empleadus emple%rowtype;
    current_dept emple.dept_no%type;
    count_per_dept number;
begin
    count_per_dept := 0;
    open cur1;
    fetch cur1 into empleadus;
    
    while cur1%found loop
        current_dept := empleadus.dept_no;
        count_per_dept := 0;
        
        -- 取当前部门前2名薪资最低的员工
        while cur1%found and empleadus.dept_no = current_dept and count_per_dept < 2 loop
            dbms_output.put_line(empleadus.emp_no||'|'||empleadus.nombre||'|'||empleadus.oficio||'|'||empleadus.salario||'|'||empleadus.dept_no);
            count_per_dept := count_per_dept + 1;
            fetch cur1 into empleadus;
        end loop;
        
        -- 跳过当前部门剩余员工
        while cur1%found and empleadus.dept_no = current_dept loop
            fetch cur1 into empleadus;
        end loop;
    end loop;
    
    close cur1;
end lowemployees;

方案2:用SQL窗口函数实现(更高效)

针对大量数据,使用ROW_NUMBER()窗口函数可避免繁琐游标逻辑,性能更优且代码简洁:

纯SQL查询方式

SELECT emp_no, nombre, oficio, salario, dept_no
FROM (
    SELECT 
        e.*,
        ROW_NUMBER() OVER (PARTITION BY dept_no ORDER BY salario) AS rn
    FROM emple e
)
WHERE rn <= 2
ORDER BY dept_no, salario;

封装为存储过程

create or replace procedure lowemployees
as
begin
    FOR emp_rec IN (
        SELECT emp_no, nombre, oficio, salario, dept_no
        FROM (
            SELECT 
                e.*,
                ROW_NUMBER() OVER (PARTITION BY dept_no ORDER BY salario) AS rn
            FROM emple e
        )
        WHERE rn <= 2
        ORDER BY dept_no, salario
    ) LOOP
        dbms_output.put_line(emp_rec.emp_no||'|'||emp_rec.nombre||'|'||emp_rec.oficio||'|'||emp_rec.salario||'|'||emp_rec.dept_no);
    END LOOP;
end lowemployees;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 02:30:08