3

我有复合触发器的问题。: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: 

如果省略after部分,则结果正确:

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    
4

2 回答 2

0

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

BEFORE STATEMENT
AFTER STATEMENT
BEFORE EACH ROW
AFTER EACH ROW

参考:复合触发器部分,Oracle 11gR1 文档

以下脚本(在连接到的 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
于 2013-05-20T10:50:32.883 回答
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 绑定变量在 BEFORE EACH ROW
  • 重新排序这些部分可以使其再次工作,例如将 AFTER EACH ROW 移动到触发器的顶部
  • 一些排序给出空白:NEW,没有注释掉任何行(例如,BEFORE STATEMENT、BEFORE ROW、AFTER ROW、AFTER STATEMENT)

非常挑剔和奇怪的行为。

于 2013-05-21T06:09:16.030 回答