旧条件不等于新条件的 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>
假设我在名为 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
中没有 - 您错过了填充
AUDIT
table 中的ID
列;我选择使用序列
WHERE
子句
上述内容的组合(尤其是缺少 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>