条件旧的 Oracle 触发器不等于新的触发器,最终出现错误 PLS-00049、PL/SQL:ORA-00933



假设主表上有名为 EMPLOYEE 的数据,其中包含以下示例数据:

员工

+--------+----------+
| EMP_ID | EMP_NAME |
+--------+----------+
|    100 | Smith    |
|    200 | Clark    |
+--------+----------+

现在,如果用新数据插入表或针对现有数据更新表;则数据如下所示:员工

+--------+----------+
| EMP_ID | EMP_NAME |             
+--------+----------+
|    100 | Blake    | <---- UPDATE with different value
|    200 | Clark    | <---- UPDATE with same value
|    300 | Mary     | <---- INSERT
+--------+----------+

其中,EMP_ID 100 和 200 的行是更新操作,EMP_ID 300 的行作为其新记录插入。

我编写了触发器来捕获EMP_NAME列中的插入或更新更改,前提是 OLD emp_name不等于相应EMP_ID的新emp_name(我不希望在我的审计表中有重复的EMP_ID称为 EMPLOYEE_AUDITS(。以下是触发器:

CREATE OR REPLACE TRIGGER employee_audits_tr 
INSERT OR UPDATE ON employees 
FOR EACH ROW 
BEGIN 
IF ( inserting OR updating AND :old.emp_name <> :new.emp_name ) THEN 
INSERT INTO employee_audits(emp_id, old_emp_name,new_emp_name) 
VALUES(emp_id, :old.emp_name, :new.emp_name ) 
WHERE emp_id = :new.emp_id; 
END IF; 
END;

尝试根据上面提供的数据获得EMPLOYEE_AUDITS的输出,如下所示EMPLOYEE_AUDITS

+----+--------+--------------+--------------+
| ID | EMP_ID | OLD_EMP_NAME | NEW_EMP_NAME |
+----+--------+--------------+--------------+
|  1 |    100 | Smith        | Blake        |
|  2 |    300 | NULL         | Mary         |
+----+--------+--------------+--------------+

对于下一次迭代,当 EMPLOYEE 表再次更新时,新数据集如下所示:员工

+--------+----------+
| EMP_ID | EMP_NAME |                             
+--------+----------+
|    100 | Karla    | <---- UPDATE with NEW value  
|    200 | Clark    | <---- UPDATE with same value
|    300 | James    | <---- UPDATE with NEW value
|    400 | Sofia    | <---- INSERT                
+--------+----------+

EMPLOYEE_AUDITS表中应包含如下值:
EMPLOYEE_AUDITS

+----+--------+--------------+--------------+
| ID | EMP_ID | OLD_EMP_NAME | NEW_EMP_NAME |
+----+--------+--------------+--------------+
|  1 |    100 | Blake        | Karla        |
|  2 |    300 | Mary         | James        |
|  3 |    400 | NULL         | Sofia        |
+----+--------+--------------+--------------+

使用触发器,我收到如下错误:

错误 PLS-00049, PL/SQL: ORA-00933

我提前感谢大家,并感谢任何帮助。

谢谢,
里查

触发器代码错误:

  • 触发器声明中没有BEFORE关键字
  • 已经说过它会在插入或更新之前触发;你也不必把它放到IF中。
  • 如果你把它放在那里,那么要小心:当有OR时,如果你不把运算符括在括号里,你会破坏一切。那将是if (updating or inserting) and (:old.emp_name <> :new.emp_name) then ....
  • 注意空值!插入时,没有旧值
  • INSERT INTO中没有WHERE条款
  • 您错过了填充AUDIT表中的ID列;我选择使用序列

上面所说的(特别是缺少BEGIN和多余的WHERE(的组合导致了ORA-00933(SQL命令未正确结束(错误。

下面是一个完整的示例:

SQL> create table employees (emp_id number, emp_name varchar2(20));
Table created.
SQL> insert into employees
2  select 100, 'smith' from dual union all
3  select 200, 'clark' from dual;
2 rows created.
SQL> create table employee_audits
2    (id number, emp_id number, old_emp_name varchar2(20), new_emp_name varchar2(20));
Table created.
SQL> create sequence seq_audit;
Sequence created.
SQL>
SQL> create or replace trigger employee_audits_tr
2    before insert or update on employees
3    for each row
4  begin
5    if nvl(:old.emp_name, '-1') <> nvl(:new.emp_name, '-1')
6    then
7       insert into employee_audits
8         (id, emp_id, old_emp_name, new_emp_name)
9         values
10         (seq_audit.nextval, :new.emp_id, :old.emp_name, :new.emp_name);
11    end if;
12  end;
13  /
Trigger created.

测试:

SQL> update employees set emp_name = 'blake' where emp_id = 100;
1 row updated.
SQL> update employees set emp_name = 'clark' where emp_id = 200;
1 row updated.
SQL> insert into employees values (300, 'mary');
1 row created.
SQL> select * From employee_audits;
ID     EMP_ID OLD_EMP_NAME         NEW_EMP_NAME
---------- ---------- -------------------- --------------------
1        100 smith                blake
2        300                      mary
SQL>

[编辑:每个员工只保留一行]

在我看来,你不应该这样做——如果你丢失了所有以前的修改,这是什么样的审计?无论如何,这是触发代码:

  • 首先它更新一行
  • 如果EMP_ID不存在,则UPDATE不会执行任何操作,SQL%ROWCOUNT将为 0
  • 在这种情况下,INSERT一行

.

SQL> create or replace trigger employee_audits_tr
2    before insert or update on employees
3    for each row
4  begin
5    update employee_audits set
6      old_emp_name = :old.emp_name,
7      new_emp_name = :new.emp_name
8      where emp_id = :new.emp_id ;
9
10    if sql%rowcount = 0 then
11       insert into employee_audits (id, emp_id, old_emp_name, new_emp_name)
12       values (seq_audit.nextval, :new.emp_id, :old.emp_name, :new.emp_name);
13    end if;
14  end;
15  /
Trigger created.
SQL>

最新更新