在我看来,这是一种错误的做法。业务规则不应由数据库触发器强制执行。如果我是你,我会把它放到前端应用程序中(输入新音符值的地方)。
这样做,您甚至可以通知用户正在发生的事情,并让他们决定是否要接受新值(您会根据这些条件建议)还是不接受(并且可能输入一个新值,有效值)。
正如您所注意到的,DBMS_OUTPUT.PUT_LINE
它不起作用。如果您用来更新音符值的工具能够显示它,它会。(顺便说一句,您SET SERVEROUTPUT ON
是吗?)例如,如果您使用的是 Oracle Forms,那么您什么也看不到。
RAISE_APPLICATION_ERROR
,当被调用时,结束子程序并返回用户定义的错误号和消息。但是,它也会使您所做的更新无效。即使您将触发器设置为自治事务,它也不起作用。例如:
SQL> drop table inscription;
Table dropped.
SQL> create table inscription (note number);
Table created.
SQL> insert into inscription (note) values (2);
1 row created.
SQL> create or replace trigger c3_update
2 before update of note on inscription
3 for each row
4 when (new.note < old.note * 0.9)
5 declare
6 pragma autonomous_transaction;
7 l_note inscription.note%type;
8 l_info varchar2(100);
9 begin
10 if :new.note > 0 then
11 :new.note := :old.note * 0.9;
12 l_info := 'the note can not be less than 10%';
13 elsif :new.note < 0 then
14 :new.note := 0;
15 l_info := 'the note can not be under 0';
16 end if;
17 -- Let's hope that COMMIT will save the updated value
18 select note into l_note from inscription;
19 dbms_output.put_line('Note before commit = ' || l_note);
20 commit;
21 select note into l_note from inscription;
22 dbms_output.put_line('Note after commit = ' || l_note);
23
24 -- Raise the "error", hoping that it'll just display a message,
25 -- but updated value will remain "as is"
26 raise_application_error(-20001, l_info);
27 end;
28 /
Trigger created.
SQL> set serveroutput on
SQL> update inscription set note = -1;
Note before commit = 2
Note after commit = 2
update inscription set note = -1
*
ERROR at line 1:
ORA-20001: the note can not be under 0
ORA-06512: at "SCOTT.C3_UPDATE", line 22
ORA-04088: error during execution of trigger 'SCOTT.C3_UPDATE'
SQL> select * from inscription;
NOTE
----------
2
看?note不是0
,而是保持其原始值 ( 2
)。它甚至从未得到值 0,因为触发器没有成功结束。如何检查?通过注释RAISE
命令:
SQL> create or replace trigger c3_update
2 before update of note on inscription
3 for each row
4 when (new.note < old.note * 0.9)
5 declare
6 pragma autonomous_transaction;
7 l_note inscription.note%type;
8 l_info varchar2(100);
9 begin
10 if :new.note > 0 then
11 :new.note := :old.note * 0.9;
12 l_info := 'the note can not be less than 10%';
13 elsif :new.note < 0 then
14 :new.note := 0;
15 l_info := 'the note can not be under 0';
16 end if;
17 -- Let's hope that COMMIT will save the updated value
18 select note into l_note from inscription;
19 dbms_output.put_line('Note before commit = ' || l_note);
20 commit;
21 select note into l_note from inscription;
22 dbms_output.put_line('Note after commit = ' || l_note);
23
24 -- Raise the "error", hoping that it'll just display a message,
25 -- but updated value will remain "as is"
26 --raise_application_error(-20001, l_info);
27 end;
28 /
Trigger created.
SQL> set serveroutput on
SQL> update inscription set note = -1;
Note before commit = 2
Note after commit = 2
1 row updated.
SQL> select * from inscription;
NOTE
----------
0
它可以完成工作,但是 - 无法显示消息(我已经告诉过你原因)。
如果您打算将其包含UPDATE inscription set note = its_new_value
到触发器本身中,请不要 - 您会遇到死锁,因为初始更新会触发执行更新的触发器,该触发器会调用执行更新等的触发器。
因此,据我所知,你不能做你想做的事,而不是触发器。