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

Oracle Trigger with condition old not equal to new ending up with errors PLS-00049, PL/SQL: ORA-00933

假设我在名为 EMPLOYEES 的主机 table 上有数据,样本数据如下:

员工

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

现在如果 table 插入新数据或更新现有数据;然后数据如下所示: 员工人数

+--------+----------+
| 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 列中的更改,仅当旧 emp_name 不等于新 emp_name 时相应 EMP_ID。 (我不想在我的审计 table 中有重复的 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         |
+----+--------+--------------+--------------+

对于下一次迭代,当 EMPLOYEES table 再次使用新数据集更新时,如下所示: 员工人数

+--------+----------+
| 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 table 应保持如下值:
EMPLOYEE_AUDITS

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

使用触发器,出现如下错误:

errors PLS-00049, PL/SQL: ORA-00933

在此先感谢大家的帮助。

谢谢,
里查

触发码错误:

  • 触发器声明中没有 BEFORE 关键字
  • 您已经说过它会在插入或更新之前触发;您也不必将其放入 IF
  • 如果你确实把它放在那里,那么要小心:当有 OR 时,如果你不将运算符括在括号中,你会破坏一切。那将是 if (updating or inserting) and (:old.emp_name <> :new.emp_name) then ....
  • 注意 NULL 值!插入时没有旧值
  • INSERT INTO
  • 中没有 WHERE 子句
  • 您错过了填充 AUDIT table 中的 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>