Oracle PL / SQL选择和更新

时间:2012-02-07 01:56:30

标签: sql oracle plsql oracle10g

执行此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;

2 个答案:

答案 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