假设主表上有名为 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>