执行此PL / SQL块时,我一直收到“无数据”。如果我注释掉输出行,那么一切都按照我的怀疑输出,但更新语句永远不会执行。有什么想法吗?
set serveroutput on;
Declare
TYPE type_emp IS RECORD(
emp_salary emp.salary%TYPE);
rec_emp type_emp;
v_stars varchar2(50) ;
v_count number(3);
s_num number(3);
begin
SELECT min(employee_id) into s_num from emp;
SELECT count(*) into v_count from emp;
v_count := v_count + s_num;
for i in s_num .. v_count loop
SELECT salary
into rec_emp
from emp
where employee_id = i;
if rec_emp.emp_salary <1000 then
v_stars := null;
elsif rec_emp.emp_salary >=1000 and rec_emp.emp_salary <2000 then
v_stars := '*';
elsif rec_emp.emp_salary >=2000 and rec_emp.emp_salary <3000 then
v_stars := '**';
elsif rec_emp.emp_salary >=3000 and rec_emp.emp_salary <4000 then
v_stars := '***';
elsif rec_emp.emp_salary >=4000 and rec_emp.emp_salary <5000 then
v_stars := '****';
elsif rec_emp.emp_salary >=5000 and rec_emp.emp_salary <6000 then
v_stars := '*****';
elsif rec_emp.emp_salary >=6000 and rec_emp.emp_salary <7000 then
v_stars := '******';
elsif rec_emp.emp_salary >=7000 and rec_emp.emp_salary <8000 then
v_stars := '*******';
elsif rec_emp.emp_salary >=8000 and rec_emp.emp_salary <9000 then
v_stars := '********';
elsif rec_emp.emp_salary >=9000 and rec_emp.emp_salary <10000 then
v_stars := '*********';
elsif rec_emp.emp_salary >=10000 and rec_emp.emp_salary <11000 then
v_stars := '**********';
elsif rec_emp.emp_salary >=11000 and rec_emp.emp_salary <12000 then
v_stars := '***********';
elsif rec_emp.emp_salary >=12000 then
v_stars := '************';
end if;
--dbms_output.put_line(rec_emp.emp_salary || ' ' || i || ' '|| v_stars);
update emp set emp.stars = v_stars where employee_id = i;
end loop;
end;
答案 0 :(得分:8)
您正在使用一种非常不寻常的方法来遍历表中的所有记录。您的方法假定员工ID是连续的(即没有间隙)。它也有一个一个错误。
假设您的表格中包含以下行:
100
101
102
103
104
首先,您获得最低员工ID:s_num = 100
。
然后,您获得了记录数:v_count = 5
。
最后,将这些添加到一起以获得上限:s_num + v_count = 105
你现在能看到你的循环问题吗?在最后一次迭代中,您的查询:
SELECT salary
into rec_emp
from emp
where employee_id = i;
将查找员工ID 105,这会引发NO_DATA_FOUND
。 DBMS_OUTPUT调用已经完成,所以你会看到输出;但是未处理的异常会导致回滚,这意味着您的UPDATE将被撤消。
相反,你可以使你的循环更简单,例如:
FOR rec_emp IN (SELECT employee_id, salary AS emp_salary FROM emp) LOOP
if rec_emp.emp_salary <1000 then
v_stars := null;
elsif <snip>
...
end if;
--dbms_output.put_line(rec_emp.emp_salary || ' ' || i || ' '|| v_stars);
update emp set emp.stars = v_stars where employee_id = i;
END LOOP;
上面的代码也稍微有点效率。它可以变得更有效率,但我不希望这个答案远远超过你迄今为止的目标。
我希望这会有所帮助。
答案 1 :(得分:1)
@Jeffrey Kemp的回答是完全正确的。此外,您可以将其简化为单个陈述(正如@John Doyle的评论所暗示的那样):
UPDATE emp
SET emp.stars =
CASE WHEN rec_emp.emp_salary < 1000
THEN NULL
ELSE LPAD('*', LEAST(FLOOR(rec_emp.emp_salary / 1000), 12), '*') END