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

问题描述 投票:0回答:2

我对复合触发器有疑问。 :当指定 after 部分时,new.value 在 before every row 部分中为空白/空。

创建表格部分:

  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

但是当我在每行语句之后添加时:

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    
oracle triggers
2个回答
0
投票

计时点部分的顺序很重要并且需要是:

BEFORE STATEMENT
AFTER STATEMENT
BEFORE EACH ROW
AFTER EACH ROW

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

以下脚本(在连接到

Oracle Database 11g Express Edition Release 11.2.0.2.0 - Production

的 Oracle SQL Developer 中运行)
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

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 中的绑定变量注释掉该行,您将得到空白:BEFORE EACH ROW 中的新绑定变量
  • 重新排序各部分可以使其再次工作,例如将“每行之后”移动到触发器的顶部
  • 某些排序给出空白:NEW,没有注释掉任何行(例如 BEFORE STATMENT、BEFORE ROW、AFTER ROW、AFTER STATMENT)

非常挑剔和奇怪的行为。

© www.soinside.com 2019 - 2024. All rights reserved.