【问题标题】:there is few mistake in trigger help me to solve that problem触发器几乎没有错误帮助我解决这个问题
【发布时间】:2021-02-11 00:33:39
【问题描述】:

创建触发器 不允许更新员工的工资 谁在销售部门。 Emp(no,name,dno,salary,designamtion) 部门(dno,名称,位置)

错误:TRIGGER MYTRIGGER1 行/列:6/11 PLS-00049:绑定变量“OLD.EMP”错误 行/列:6/31 PLS-00049:错误的绑定变量“OLD.EMP”

DROP TABLE EMP;
DROP TABLE DEPT;
CREATE TABLE Dept
(
    dno NUMBER PRIMARY KEY,
    name VARCHAR(15),
    location VARCHAR(15)  );
CREATE TABLE Emp
(
    no NUMBER PRIMARY KEY,
    name VARCHAR(15),
    dno NUMBER,
    salary NUMBER,
    designamtion VARCHAR(15),
    FOREIGN KEY(dno) REFERENCES Dept(dno)  );

insert into DEPT values (1,'SALES','GUJARAT');
insert into DEPT values (2,'MARKETING','UP');
insert into DEPT values (3,'MANUFACTURING','MP');
insert into DEPT values (4,'DEALING','VAPI');
insert into DEPT values (5,'SELL','TAPI');

insert into EMP values (1,'AMAN',2,45400,'MANAGER');
insert into EMP values (2,'BHAMAN',5,20000,'GM');
insert into EMP values (3,'CHAMAN',3,34400,'ADVISOR');
insert into EMP values (4,'DAMAN',4,75400,'WORKER');
insert into EMP values (5,'KHAMAN',1,42400,'MANAGER');


CREATE OR REPLACE trigger MYTRIGGER1
BEFORE UPDATE OF SALARY ON EMP
for each row
declare
    hmmm VARCHAR(15);
begin
    select Dept.name into hmmm 
    from Dept, Emp
    where :old.emp.no=no and  :old.emp.dno=Dept.dno;
    dbms_output.put_line(hmmm);
end;

【问题讨论】:

    标签: sql database oracle plsql oracle11g


    【解决方案1】:

    您不需要为触发器所在的表设置别名。这将编译得很好:

    CREATE OR REPLACE trigger MYTRIGGER1
    BEFORE UPDATE OF SALARY ON EMP
    for each row
    declare
        hmmm VARCHAR(15);
    begin
        select Dept.name into hmmm 
        from Dept, Emp
        where :old.no=no and  :old.dno=Dept.dno;
        dbms_output.put_line(hmmm);
    end;
    

    但是,当您更新表时,此触发器将失败。您不能从触发器主体中的表本身中进行选择。这将引发变异表错误。由于这是一项任务,我将把研究留给你。

    【讨论】:

      【解决方案2】:

      正如 Koen 所说,您的代码将遭受变异表错误。

      你很幸运 - 你不必从刚刚更新的表中选择emp 表,对吗?) - 你在:new.dno 中拥有你需要的一切。所以:

      SQL> create or replace trigger mytrigger1
        2    before update of salary on emp
        3    for each row
        4  declare
        5    hmmm varchar2(15);
        6  begin
        7    select d.name
        8      into hmmm
        9      from dept d
       10      where d.dno = :new.dno;
       11
       12    dbms_output.put_line('Department name = ' || hmmm);
       13  end;
       14  /
      
      Trigger created.
      

      测试:

      SQL> set serveroutput on
      SQL>
      SQL> update emp set salary = 1000 where no = 1;
      Department name = MARKETING
      
      1 row updated.
      
      SQL> update emp set salary = 1000;
      Department name = MARKETING
      Department name = SELL
      Department name = MANUFACTURING
      Department name = DEALING
      Department name = SALES
      
      5 rows updated.
      
      SQL>
      

      【讨论】:

        【解决方案3】:

        您的请求是一个触发器,不允许销售部门的员工执行某些操作。即使已编译,您的触发器也不会这样做。两个问题:

        1. dbms_output 不会阻止任何事情,它只是“打印”一条消息。
        2. 它会阻止对薪水的任何更新,除非同时更新了 emp.dno 或 emp.no。

        首先(在肥皂盒上起床)。您正在执行业务规则。这不应该在触发器中完成。它应该在您的应用程序的业务规则引擎或数据库约束中完成,或者如果您想在这两个方面都非常小心。现在触发器将执行执行,但违反业务规则的行为应该非常明显且易于查找,触发器成为操作的副作用,隐藏起来且难以查找。 (够了,下车肥皂盒)。

        您正在寻找的预防方法是raise_application_error。而且您希望触发器中的代码尽可能少。在这种情况下,您拥有从 EMP 表到 pesudo 行 :old 和 :new 所需的一切,因此没有理由加入您的表。但是,您确实需要查看特定部门。太糟糕了 Oracle 将 Exists 谓词限制为引入子选择,这将是结构的完美位置:

        If EXISTS (selects ...) then ...
        

        但这不可用。下面使用一种反转需求的技术。也就是说,它选择不想要的东西,如果发现它会引发异常,如果没有找到它会抑制 Oracle 引发的错误。所以:

        create or replace trigger mytrigger1
           before update of salary on emp
           for each row
        declare
           hmmm  varchar2(01);   
        begin
            select null
              into hmmm
              from dept d   
             where d.dno = :old.dno
               and d.name = 'SALES';
             
             raise_application_error(-20199, 'Can not update salary for Employee in Sales.');
        exception 
            when no_data_found then null;
        end mytrigger1; 
        

        这有时被称为“编程异常”,不是一般推荐的过程,但有时它很有用。见fiddle here。 这里有一个悬而未决的问题没有解决。如果销售部门的员工也在调动部门,他们是否可以更改薪水。 IE。以下是成功还是失败?

        update emp e
           set dno = 2
             , salary = salary + 5000
         where e.no = 5;
        
        
        
          
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2022-10-17
          • 2021-03-07
          • 2019-05-22
          • 2020-08-06
          • 1970-01-01
          • 1970-01-01
          • 2022-12-04
          相关资源
          最近更新 更多