如何检查:复合触发器中的新值,何时指定after语句?

时间:2013-05-19 18:20:54

标签: oracle triggers

复合触发器有问题。 :当指定部分之后的部分时,new.value在每行部分之前的中为空/空。

创建表格部分:

  DROP TABLE test_tab;
  CREATE TABLE test_tab
    ( ID_TEST_TAB NUMBER
    );
  INSERT INTO test_tab VALUES
    (1
    );
  INSERT INTO test_tab VALUES
    (2
    );

触发器的部分:

CREATE OR REPLACE TRIGGER TEST_COMP_TRIGGER
  FOR UPDATE ON test_tab
  COMPOUND TRIGGER   
---
BEFORE EACH ROW
IS
BEGIN
  dbms_output.put_line('TEST_COMP_TRIGGER:  BEFORE EACH ROW');
  dbms_output.put_line('>>>> old: ' || :old.ID_TEST_TAB );
  dbms_output.put_line('>>>> new: ' || :new.ID_TEST_TAB );
  NULL;
END BEFORE EACH ROW;
---
AFTER STATEMENT
IS
BEGIN
  NULL;
END AFTER STATEMENT;
END TEST_COMP_TRIGGER;
/

后:

UPDATE test_tab SET test_tab.ID_TEST_TAB=test_tab.ID_TEST_TAB;

我明白了:

TEST_COMP_TRIGGER:  BEFORE EACH ROW
>>>> old: 1
>>>> new: 
TEST_COMP_TRIGGER:  BEFORE EACH ROW
>>>> old: 2
>>>> new: 

如果省略之后的部分,结果是正确的:

CREATE OR REPLACE TRIGGER TEST_COMP_TRIGGER
  FOR UPDATE ON test_tab
  COMPOUND TRIGGER
---
BEFORE EACH ROW
IS
BEGIN
  dbms_output.put_line('TEST_COMP_TRIGGER:  BEFORE EACH ROW');
  dbms_output.put_line('>>>> old: ' || :old.ID_TEST_TAB );
  dbms_output.put_line('>>>> new: ' || :new.ID_TEST_TAB );
  NULL;
END BEFORE EACH ROW;
END TEST_COMP_TRIGGER;
/

后:

UPDATE test_tab SET test_tab.ID_TEST_TAB=test_tab.ID_TEST_TAB;

我明白了:

TEST_COMP_TRIGGER:  BEFORE EACH ROW
>>>> old: 1
>>>> new: 2
TEST_COMP_TRIGGER:  BEFORE EACH ROW
>>>> old: 2
>>>> new: 2

为什么在第一种情况下:new.value是空白的?

-----------更新 我按照你的指示: 代码:

create or replace trigger TEST_COMP_TRIGGER
FOR UPDATE ON test_tab  
COMPOUND TRIGGER   
---- BEFORE
  BEFORE STATEMENT
  IS
  BEGIN
    dbms_output.put_line('TEST_COMP_TRIGGER:  BEFORE STATEMENT');
    NULL;
  END BEFORE STATEMENT;
---- AFTER
  AFTER STATEMENT IS
  BEGIN
    dbms_output.put_line('TEST_COMP_TRIGGER:  AFTER STATEMENT');
    NULL;
  END AFTER STATEMENT;
---- BEFORE EACH
  BEFORE EACH ROW IS
  BEGIN
    dbms_output.put_line('TEST_COMP_TRIGGER:  BEFORE EACH ROW');
    dbms_output.put_line('>>>> old: ' || :old.ID_TEST_TAB );
    dbms_output.put_line('>>>> new: ' || :new.ID_TEST_TAB );
    NULL;
  END BEFORE EACH ROW;
END TEST_COMP_TRIGGER;
/

-----
SET serveroutput ON format wraped;
UPDATE test_tab SET test_tab.ID_TEST_TAB=test_tab.ID_TEST_TAB;
/

给出预期结果:

    2 rows updated.
TEST_COMP_TRIGGER:  BEFORE STATEMENT
TEST_COMP_TRIGGER:  BEFORE EACH ROW
>>>> old: 1
>>>> new: 1
TEST_COMP_TRIGGER:  BEFORE EACH ROW
>>>> old: 2
>>>> new: 2
TEST_COMP_TRIGGER:  AFTER STATEMENT

但是当我添加AFTER EACH ROW声明时:

create or replace trigger TEST_COMP_TRIGGER
FOR UPDATE ON test_tab  
COMPOUND TRIGGER   
---- BEFORE
  BEFORE STATEMENT
  IS
  BEGIN
    dbms_output.put_line('TEST_COMP_TRIGGER:  BEFORE STATEMENT');
    NULL;
  END BEFORE STATEMENT;
---- AFTER
  AFTER STATEMENT IS
  BEGIN
    dbms_output.put_line('TEST_COMP_TRIGGER:  AFTER STATEMENT');
    NULL;
  END AFTER STATEMENT;
---- BEFORE EACH
  BEFORE EACH ROW IS
  BEGIN
    dbms_output.put_line('TEST_COMP_TRIGGER:  BEFORE EACH ROW');
    dbms_output.put_line('>>>> old: ' || :old.ID_TEST_TAB );
    dbms_output.put_line('>>>> new: ' || :new.ID_TEST_TAB );
    NULL;
  END BEFORE EACH ROW;
---- AFTER EACH  
  AFTER EACH ROW
  IS
  BEGIN
    dbms_output.put_line('TEST_COMP_TRIGGER:  AFTER EACH ROW');
  END AFTER EACH ROW;
END TEST_COMP_TRIGGER;
/

-----
SET serveroutput ON format wraped;
UPDATE test_tab SET test_tab.ID_TEST_TAB=test_tab.ID_TEST_TAB;
/

我还是空着:新:

2 rows updated.
TEST_COMP_TRIGGER:  BEFORE STATEMENT
TEST_COMP_TRIGGER:  BEFORE EACH ROW
>>>> old: 1
>>>> new: 
TEST_COMP_TRIGGER:  AFTER EACH ROW
TEST_COMP_TRIGGER:  BEFORE EACH ROW
>>>> old: 2
>>>> new: 
TEST_COMP_TRIGGER:  AFTER EACH ROW
TEST_COMP_TRIGGER:  AFTER STATEMENT    

2 个答案:

答案 0 :(得分:0)

时间点部分的顺序很重要,需要:

BEFORE STATEMENT
AFTER STATEMENT
BEFORE EACH ROW
AFTER EACH ROW

参考:Compound Trigger Sections, Oracle 11gR1 docs

以下脚本(在Oracle SQL Developer中运行,连接到Oracle Database 11g Express Edition Release 11.2.0.2.0 - Production

DROP TABLE test_tab;
CREATE TABLE test_tab ( ID_TEST_TAB NUMBER);
INSERT INTO test_tab VALUES (1);
INSERT INTO test_tab VALUES (2);

create or replace trigger TEST_COMP_TRIGGER
FOR UPDATE ON test_tab  
COMPOUND TRIGGER   

  AFTER STATEMENT IS
  BEGIN
    dbms_output.put_line('TEST_COMP_TRIGGER:  AFTER STATEMENT');
    NULL;
  END AFTER STATEMENT;

  BEFORE EACH ROW IS
  BEGIN
    dbms_output.put_line('TEST_COMP_TRIGGER:  BEFORE EACH ROW');
    dbms_output.put_line('>>>> old: ' || :old.ID_TEST_TAB );
    dbms_output.put_line('>>>> new: ' || :new.ID_TEST_TAB );
    NULL;
  END BEFORE EACH ROW;

END TEST_COMP_TRIGGER;
/

set serveroutput on format wraped;
UPDATE test_tab SET test_tab.ID_TEST_TAB=test_tab.ID_TEST_TAB+1;
/

产生输出:

table TEST_TAB dropped.
table TEST_TAB created.
1 rows inserted.
1 rows inserted.
TRIGGER TEST_COMP_TRIGGER compiled
2 rows updated.
TEST_COMP_TRIGGER:  BEFORE EACH ROW
>>>> old: 1
>>>> new: 2
TEST_COMP_TRIGGER:  BEFORE EACH ROW
>>>> old: 2
>>>> new: 3
TEST_COMP_TRIGGER:  AFTER STATEMENT

将它们换成错误的顺序,输出结束为:

table TEST_TAB dropped.
table TEST_TAB created.
1 rows inserted.
1 rows inserted.
TRIGGER TEST_COMP_TRIGGER compiled
2 rows updated.
TEST_COMP_TRIGGER:  BEFORE EACH ROW
>>>> old: 1
>>>> new: 
TEST_COMP_TRIGGER:  BEFORE EACH ROW
>>>> old: 2
>>>> new: 
TEST_COMP_TRIGGER:  AFTER STATEMENT

答案 1 :(得分:0)

以下脚本按预期工作。

DROP TABLE test_tab;
CREATE TABLE test_tab ( IDNO NUMBER);
INSERT INTO test_tab VALUES (1);
INSERT INTO test_tab VALUES (2);

create or replace trigger TEST_COMP_TRIGGER
FOR UPDATE ON test_tab  
COMPOUND TRIGGER   
---- BEFORE
  BEFORE STATEMENT IS
  BEGIN
    dbms_output.put_line('TEST_COMP_TRIGGER:  BEFORE STATEMENT');
  END BEFORE STATEMENT;
---- AFTER
  AFTER STATEMENT IS
  BEGIN
    dbms_output.put_line('TEST_COMP_TRIGGER:  AFTER STATEMENT');
  END AFTER STATEMENT;
---- BEFORE EACH
  BEFORE EACH ROW IS
  BEGIN
    dbms_output.put('TEST_COMP_TRIGGER:  BEFORE EACH ROW');
    dbms_output.put(' old: ' || :old.IDNO || ' new: ' || :new.IDNO);
    :New.IDNO := :new.IDNO + 1;
    dbms_output.put_line(' old: ' || :old.IDNO || ' new: ' || :new.IDNO);
  END BEFORE EACH ROW;
---- AFTER EACH  
  AFTER EACH ROW IS
  BEGIN
    dbms_output.put('TEST_COMP_TRIGGER:  AFTER EACH ROW');
    dbms_output.put_line(' old: ' || :old.IDNO || ' new: ' || :new.IDNO);
  END AFTER EACH ROW;
END TEST_COMP_TRIGGER;
/

set serveroutput on format wraped;
UPDATE test_tab SET test_tab.IDNO=test_tab.IDNO+1;
/

生成输出:

table TEST_TAB dropped.
table TEST_TAB created.
1 rows inserted.
1 rows inserted.
TRIGGER TEST_COMP_TRIGGER compiled
2 rows updated.
TEST_COMP_TRIGGER:  BEFORE STATEMENT
TEST_COMP_TRIGGER:  BEFORE EACH ROW old: 1 new: 2 old: 1 new: 3
TEST_COMP_TRIGGER:  AFTER EACH ROW old: 1 new: 3
TEST_COMP_TRIGGER:  BEFORE EACH ROW old: 2 new: 3 old: 2 new: 4
TEST_COMP_TRIGGER:  AFTER EACH ROW old: 2 new: 4
TEST_COMP_TRIGGER:  AFTER STATEMENT

现在为了好玩。

  • 在AFTER EACH ROW中使用绑定变量注释掉该行,你得到空白:每个行前的新绑定变量
  • 重新排序这些部分可以让它再次起作用,例如将每个行后移动到触发器的顶部
  • 某些排序为空白:NEW没有任何行注释掉(在声明之前,行之前,行之后,例如声明之后)

非常挑剔和奇怪的行为。