我有一个任务:
根据等级在emp表中编写更新工资(工资*增量%)的程序。使用函数来增加
这是我的程序:
CREATE OR REPLACE
PROCEDURE sal_incre
IS
CURSOR c_cur
IS
SELECT * FROM emp_task;
BEGIN
UPDATE emp_task SET sal = sal + sal_incr(grade_id);
FOR rec IN c_cur
LOOP
dbms_output.put_line(rec.empno||','||rec.ename||','||rec.sal);
END LOOP;
END;
这是我的功能代码:
CREATE OR REPLACE
FUNCTION sal_incr(
p_grade NUMBER)
RETURN
IS
v_inc NUMBER;
BEGIN
SELECT raise_percent
INTO v_inc
FROM sal_inc
WHERE grade_id IN
(SELECT grade_id FROM emp_task WHERE grade_id = p_grade
);
RETURN v_inc;
COMMIT;
END;
当我打电话给我的程序时:
ORA-04091: table SCOTT.EMP_TASK is mutating, trigger/function may not see it
ORA-06512: at "SCOTT.SAL_INCR", line 8
ORA-06512: at "SCOTT.SAL_INCRE", line 6
ORA-06512: at line 2
我做错了什么?
答案 0 :(得分:1)
您的函数指的是您在调用该函数时在该过程中使用的同一个表,这是导致此错误的原因。您正在以可能导致不确定(或令人困惑)结果的方式同时更新和查询它,即使您没有查询要更新的列。 Oracle在这里保护您自己。
在你正在做的功能中:
SELECT raise_percent
INTO v_inc
FROM sal_inc
WHERE grade_id IN
(SELECT grade_id FROM emp_task WHERE grade_id = p_grade
);
此处无需查看emp_task
表。除非您已经传递了一个不存在的值(这不能从您的过程中发生),否则子查询只能返回原始的p_grade
参数值,因此它与以下内容相同:
SELECT raise_percent
INTO v_inc
FROM sal_inc
WHERE grade_id = p_grade;
如果这样做,该函数不再引用emp_task
,因此当它作为更新的一部分被调用时,它不会抛出变异的触发器/函数错误。
并且您的函数不应该发出COMMIT
- 让调用过程,或者最好是调用过程的会话,决定是应该提交还是回滚谁。
此外,从标题和列名称看起来raise_percent
是一个百分比,因此您需要使用它来查找要乘以的值 - 您不应该添加百分比数字。例如,如果在2%加注时为您提供值2,则需要在您的过程中执行此操作:
UPDATE emp_task SET sal = sal * (1 + (sal_incr(grade_id)/100));
或者更整洁地让你的函数返回1 + (raise_percent/100)
并执行:
UPDATE emp_task SET sal = sal * sal_incr(grade_id);
答案 1 :(得分:0)
更改以下程序:
create or replace
procedure sal_incre
is
cursor c_cur is
select distinct e.grade_id,e.ename,e.sal from sal_inc s
join emp_task e on e.grade_id = s.grade_id order by e.ename ;
v_incr number;
begin
for f_cur in c_cur
loop
v_incr := sal_incr(f_cur.grade_id);
update emp_task set sal = sal + v_incr;
dbms_output.put_line('Emp Name : '||f_cur.ename||','
||' Sal:'||f_cur.sal||','||' Grade: '||f_cur.grade_id);
end loop;
end;