2012-03-17 58 views

回答

4

我假定你的意思是你有一个行级触发器,而不是一个模式级触发器。例如,某人在架构中的某个表上执行DDL时会触发模式级别的触发器。当您谈论架构级触发器时,谈论新旧值是毫无意义的。

如果我们在谈论行级触发器,我假设您只对UPDATE报表感兴趣。如果你插入或删除数据,你自然会改变表中的每一列。

因此,如果我们正在讨论在UPDATE上触发的行级触发器,则可以使用UPDATING函数。这会告诉你某个特定列是否正在更新。然而,它并不一定告诉你数据正在改变。声明

UPDATE table_name 
    SET col1 = col1; 

更新COL1的每一行中TABLE_NAME,但实际上并没有改变任何数据。如果这是可以接受的,你可以这样做

CREATE TRIGGER trg_table_name 
    BEFORE UPDATE ON table_name 
    FOR EACH ROW 
BEGIN 
    IF(updating('COL1')) 
    THEN 
    <<col1 was updated>> 
    END IF; 

    IF(updating('COL2')) 
    THEN 
    <<col2 was updated>> 
    END IF; 

    ... 
END; 

你可以做的是更加动态的只是在循环中的数据USER_TAB_COLS,即

SQL> ed 
Wrote file afiedt.buf 

    1 create table foo (
    2 col1 number, 
    3 col2 number, 
    4 col3 number 
    5*) 
SQL>/

Table created. 

SQL> create trigger trg_foo 
    2 before update on foo 
    3 for each row 
    4 begin 
    5 for cols in (select * 
    6     from user_tab_cols 
    7     where table_name = 'FOO') 
    8 loop 
    9  if updating(cols.column_name) 
10  then 
11  dbms_output.put_line('Updated ' || cols.column_name); 
12  end if; 
13 end loop; 
14 end; 
15/

Trigger created. 

SQL> set serveroutput on; 
SQL> insert into foo values(1, 2, 3); 

1 row created. 

SQL> update foo 
    2  set col2 = col2 + 1, 
    3   col3 = col3 * 2; 
Updated COL2 
Updated COL3 

1 row updated. 

虽然这可以告诉你所有正在更新的列,但是,主要的缺点是,有没有办法访问类似的时尚动感的:new:old值。因此,您可以发现COL2已更新,但您无法确定:new.col2:old.col2值是不是静态引用这些值。

根据您要解决的问题,您可以通过查看数据字典中的数据来编写动态生成触发器的代码。沿着这个块的东西线会产生打印出所有的:new

DECLARE 
    l_tbl_name VARCHAR2(100) := 'FOO'; 
    l_sql_stmt VARCHAR2(4000); 
BEGIN 
    l_sql_stmt := 'CREATE OR REPLACE TRIGGER trg_' || l_tbl_name || 
       ' BEFORE UPDATE ON ' || l_tbl_name || 
       ' FOR EACH ROW ' || 
       'BEGIN '; 
    FOR cols IN (SELECT * 
       FROM user_tab_cols 
       WHERE table_name = l_tbl_name) 
    LOOP 
    l_sql_stmt := l_sql_stmt || 
        ' IF UPDATING(''' || cols.column_name || ''') ' || 
        ' THEN ' || 
        ' dbms_output.put_line(:new.' || cols.column_name || '); ' || 
        ' END IF; '; 
    END LOOP; 
    l_sql_stmt := l_sql_stmt || ' END; '; 
    dbms_output.put_line(l_sql_stmt); 
    EXECUTE IMMEDIATE l_sql_stmt; 
END; 
+0

谢谢!而已!, – destiny 2012-03-19 09:56:32

2
  :old   :new 
======================================================= 
insert | null   | new value to be inserted 
update | old value | new value to be updated 
delete | old value | null 
======================================================= 

上述值是参考称为行级触发器,这意味着被触发的每一行每次烧制。

上面的表格显示了关于上述dml语句的新旧值,我们举个例子。

Insert into abc (1,'gaurav soni',pune);--empid,name,city 

假设我有表ABC一个触发器,它插入到表ABC时,检查城市是否出现在位置表或不(我知道我们可以用外键约束做到这一点),但是这是一个例子,所以我们可以参考:new.city这个城市,但是因为它的值是null,所以在插入的情况下我们不能指:old .city

update情况下,我们可以参考两个:new and :old value

delete大家可以参考情况下,只有old value作为new value是在deleting情况null

注意:在inserting情况下的delete:old情况下使用的:new不会给你compile time error,但肯定会繁荣,给你run time error 您可以使用INSERTING,DELETING子句来避免这种情况。

+0

谢谢某特定表的触发器,但我比较每列的唯一途径?我搜索了一个函数,它给了我更改的列 – destiny 2012-03-17 23:11:50

+0

@destiny:我没有得到你要找的东西,请详细说明你的答案,可能是贾斯汀帮助你的答案,但他也是假设,请详细说明其他人可能会明白你在找什么。 – 2012-03-18 04:54:56