让我们说员工表如下
EID ENAME DEPTNO SALARY
1 john 10 100
2 jau 10 300
3 cau 10 200
4 cha 20 200
5 cwea 20 500
6 dan 20 200
7 an 20 300
我必须检查是否添加了新员工,新员工薪水应该大于该部门的平均薪水,这应该在触发器中完成。
所以我创建了触发器,如下所示
create or replace trigger tg_emp before insert on employee for each row
declare
avgsal number;
highsalary EXCEPTION;
BEGIN
select avg(salary) into avgsal from employee where deptno = :NEW.deptno;
if :NEW.salary < avgsal
then
raise highsalary;
end if;
EXCEPTION
when highsalary then
Raise_Application_Error (-20343, 'salary is less than the avg salary in this
department');
WHEN others THEN
Raise_Application_Error (-20353, 'other error probably table mutation
error');
END;
如您所知,此代码仅适用于下面的单个插入
insert into employee values (8, 'jj', 10, 500);
但如果它是一次多次插入,如
insert into employee
select seq_emp.next, 'ffgg', 10, 400 from all_tab_columns where rownum < 5;
它会引发表突变错误(我知道上面的插入没有意义,但我在一个语句中只将其用作多插入的示例)。
那么我们如何使用全局临时表来解决这个问题呢?
我想我能够使用1 GTT和1之前的语句触发器和1之前的行触发器来解决它,如下所示
CREATE GLOBAL TEMPORARY TABLE employee_GTT (
id NUMBER,
name VARCHAR2(20),
deptno number,
salary number
)
ON COMMIT DELETE ROWS;
触发前的语句级别
create or replace trigger emp_avg_load before insert on employee
begin
insert into dept_avg
select deptno, avg(salary), count(deptno) from employee group by deptno;
dbms_output.put_line('getting data from GTT');
end;
触发前的行级
create or replace trigger tg_emp before insert on employee for each row
declare
avgsal number;
ct number;
highsalary EXCEPTION;
BEGIN
avgsal := :new.salary;
select avgsal, count into avgsal, ct from dept_avg where deptno =
:NEW.deptno;
if :NEW.salary < avgsal
then
raise highsalary;
else
update dept_avg
set count = count +1,
avgsal = (avgsal+:NEW.salary)/(count+1)
where deptno = :NEW.deptno;
end if;
EXCEPTION
when highsalary then
Raise_Application_Error (-20343, 'salary is less than the avg salary in this
department');
WHEN others THEN
Raise_Application_Error (-21343, 'some other error');
END;
如果我弄错了,请纠正我。
答案 0 :(得分:0)
首先使用临时表的方式是个好主意。
但是,您在交易期间更新平均工资 的方式 会向我显示 错误 。实际上,根据Oracle如何处理更新(插入顺序),您将得不到相同的结果。
您遇到困难,因为您的要求不够明确。
我不认为在插入行时更改平均工资是真实的用例。您必须在事务级别考虑它:因此,平均工资在事务发生之前定义为。因此,在插入时无需进行平均更改。只是让交易期间的平均值保持不变。
我会删除此部分:
else
update dept_avg
set count = count +1
, avgsal = (avgsal+:NEW.salary)/(count+1)
where deptno = :NEW.deptno;