Plsql 更新触发器PL/SQL Oracle

Plsql 更新触发器PL/SQL Oracle,plsql,oracle11g,triggers,Plsql,Oracle11g,Triggers,我有一个具有以下结构的表: create table treballa ( code varchar2(4), name varchar2(20), director varchar2(4), department number, salary int, primary key (code), foreign key (director) references treballa(code) ) 我需要创建一个触发器来检查更新员工的部门号,该部门所有员工之间的总工资是否不超

我有一个具有以下结构的表:

create table treballa (
code varchar2(4), 
 name varchar2(20), 
 director varchar2(4), 
department number, 
salary int,
 primary key (code), 
 foreign key (director) references treballa(code) 
) 
我需要创建一个触发器来检查更新员工的部门号,该部门所有员工之间的总工资是否不超过10000,但我真的不知道该怎么做。。。你能帮帮我吗?多谢各位

编辑:

结束编辑/

更新时出错:

[42000][4091]ORA-04091:表特殊。特雷巴拉正在变异, 触发器/函数可能看不到它ORA-06512:at “SPECIAL.CONTROLSALARIDEPT”,第14行ORA-04088:执行期间出错 触发器'SPECIAL.CONTROLSALARIDEPT'的


对不起,我对甲骨文很陌生,我需要这个触发器的帮助,我不知道我现在做的是否正确。。。。触发器的第一部分“如果插入”工作正常,问题在于更新…

尝试复合触发器:

CREATE OR REPLACE TRIGGER compound_trigger_name
FOR  INSERT OR UPDATE OF salary ON treballa
COMPOUND TRIGGER

  TYPE Departments_t   IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
  Departments          Departments_t;

     BEFORE EACH ROW IS
     BEGIN
        -- collect updated or inserted departments 
        Departments( :new.department ) := :new.department;
     END BEFORE EACH ROW;

     AFTER STATEMENT IS
        sum_sal NUMBER;
     BEGIN
      -- for each updated department check the restriction
      FOR dept IN Departments.FIRST .. Departments.LAST
      LOOP
         SELECT sum(salary) INTO sum_sal FROM treballa WHERE department = dept;
         IF sum_sal > 1000 THEN
            raise_application_error(-20123, 'The total salary for department '||dept||' cannot exceed 1000');
         END IF;
      END LOOP;
     END AFTER STATEMENT;

END compound_trigger_name;
/
  TYPE Departments_t   IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
  Departments          Departments_t;

==========编辑-一些问题和答案=================


Q:为什么会发生变异表错误?
答:这在文档中有描述:

触发对变异表的限制
变异表是一个表 由UPDATE、DELETE或INSERT语句或 可能会因删除级联效应而更新的表 约束

发出触发语句的会话无法查询或 修改变异表。此限制可防止触发器 看到一组不一致的数据

此限制适用于对每行使用 条款不考虑在而不是触发器中修改的视图 变异

当触发器遇到变异表时,会发生运行时错误, 触发器主体和触发器语句的效果将被滚动 返回,控件将返回给用户或应用程序。(你可以使用 复合触发器以避免突变表错误 有关详细信息,请参阅使用复合触发器以避免表发生变化 错误。)


Q:如何避免变异表错误?
答:文档建议使用复合触发器,请参见:

使用复合触发器以避免改变可以使用的表错误 避免突变表错误的复合触发器(ORA-04091) 在变异表的触发器限制中描述


Q:什么是复合触发器及其工作原理?
答:这是一个庞大的主题,请参阅此处的文档:

简言之:这是一种特殊的触发器,它可以将四种不同类型的触发器组合成一个声明:
BEFORE statement
BEFORE for each row
AFTER for each row
AFTER statant
。这使得实现一些场景变得更容易,其中需要将一些数据从一个触发器传递到另一个触发器。请研究以上链接以了解更多详细信息


问:但部门(:new.department):=:new.department;?实际做什么 答:此声明将部门号存储到关联数组中。

此数组在复合触发器的声明性部分声明:

CREATE OR REPLACE TRIGGER compound_trigger_name
FOR  INSERT OR UPDATE OF salary ON treballa
COMPOUND TRIGGER

  TYPE Departments_t   IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
  Departments          Departments_t;

     BEFORE EACH ROW IS
     BEGIN
        -- collect updated or inserted departments 
        Departments( :new.department ) := :new.department;
     END BEFORE EACH ROW;

     AFTER STATEMENT IS
        sum_sal NUMBER;
     BEGIN
      -- for each updated department check the restriction
      FOR dept IN Departments.FIRST .. Departments.LAST
      LOOP
         SELECT sum(salary) INTO sum_sal FROM treballa WHERE department = dept;
         IF sum_sal > 1000 THEN
            raise_application_error(-20123, 'The total salary for department '||dept||' cannot exceed 1000');
         END IF;
      END LOOP;
     END AFTER STATEMENT;

END compound_trigger_name;
/
  TYPE Departments_t   IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
  Departments          Departments_t;
与复合触发器相关的文档说明:

可选的声明性部分(第一部分)声明变量和 计时点段可以使用的子程序。当触发器 激发时,声明性部分在任何计时点节之前执行 本节中声明的变量和子程序 触发语句持续时间

上面的意思是,
部门
变量仅在整个处理开始时,触发器触发后初始化一次。“触发语句持续时间”意味着该变量在触发器完成后被销毁。

此语句:
Departments(:new.department):=:new.department;
在关联数组中存储一个部门编号。它位于每行部分之前的
,然后对由update/insert语句更新(或插入)的每一行执行。

:new
:old
都是伪记录,您可以在这里找到更多关于它们的信息:
简而言之:
:new.department
为当前更新的行(更新后的值)检索
department
列的新值,而
:old.department
为该列提供旧值(更新前).

当触发器选择所有更新的部门(在一个FOR-LOOP中)时,此集合稍后将用于
AFTER语句中,对于每个部门,触发
选择SUM(salary)…
,然后检查此总和是否小于1000

考虑一个简单的更新:<代码>更新TrBura设置薪水=工资+ 10 < /代码>。这是一个更新语句,但同时更改多行。我们的触发器的执行顺序如下:

  • 更新状态被触发:
    update treballa SET salary=salary+10
  • 触发器的声明性部分被执行,即:
    Departments
    变量被初始化
  • 在执行每一行之前
    部分,分别针对每个更新的行-更新的行数相同。在这里,我们从更改的行中收集所有部门
  • AFTER语句
    部分被执行。此时表已经更新-所有行都已经有了新的更新工资。我们循环遍历保存在
    部门
    中的部门,并检查每个部门的工资总和是否小于或等于1000。如果这些部门中的任何一个的工资总和大于1000,则会出现错误否则,触发器将完成,更新将完成(但无论如何都需要提交这些更改)

  • Q:什么是关联数组,为什么只是t