0

在触发触发器时,在 sql server 中,会创建 2 个临时表。一个是插入的表,其中包含触发器所属的原始表的行,其中发生了插入或更新(它包含 :NEW 值);另一个是已删除的表,它同样包含 OLD 值。

在 sql Server 中,可以在触发器中使用这些表,以便获取有关 OLD 和 NEW 值的信息。(做一个简单的例子:可以在触发器内部进行“SELECT * FROM INSERTED”,以便选择所有已进行更新的行或所有插入的行以防插入)。

很酷的一点是,可以动态调用:NEW.value 和:OLD.value,如果像我的情况一样,我想在更多表上使用相同的触发器(它们也彼此不同)。

Oracle pl sql有类似的东西吗?

4

2 回答 2

1

我认为您正在考虑审计表,请找到对插入、更新和删除进行审计的触发器

编辑:phantom建议您需要在插入审计表之前检查每一列的新旧值。这样您可以实现哪些列值发生变化。但是为此,如果多列已更新,您需要将多行插入审计表相同的记录。

我的想法是在更新/删除/插入审计表之前创建同一记录的副本。当你想要更改时,根据 source_action/source_rowid 与审计表中的先前记录进行比较

    CREATE TABLE table_for_audit
    (
       col1       NUMBER,
       col2       NUMBER,
       col3       NUMBER,
       cre_date   DATE,
       cre_user   VARCHAR2 (200)
    );

    CREATE TABLE audit_table
    (
       col1            NUMBER,
       col2            NUMBER,
       col3            NUMBER,
       cre_date        DATE,
       cre_user        VARCHAR2 (200),
       source_action   VARCHAR2 (1),
       source_rowid
    );

    CREATE OR REPLACE TRIGGER trg_table_audit
       BEFORE INSERT OR UPDATE OR DELETE
       ON table_for_audit
       REFERENCING NEW AS NEW OLD AS OLD
       FOR EACH ROW
    DECLARE
       v_source_action   VARCHAR2 (1);
    BEGIN
       IF INSERTING
       THEN
          v_source_action := 'I';
          v_source_rowid := :NEW.ROWID;
       ELSIF UPDATING
       THEN
          v_source_action := 'U';
          v_source_rowid := :OLD.ROWID;
       ELSIF DELETING
       THEN
          v_source_action := 'D';
          v_source_rowid := :OLD.ROWID;
       END IF;


       IF INSERTING OR UPDATING
       THEN
          INSERT INTO audit_table (col1,
                                   col2,
                                   col3,
                                   cre_date,
                                   cre_user,
                                   source_action,
                                   source_rowid)
               VALUES (:NEW.col1,
                       :NEW.col2,
                       :NEW.col3,
                       SYSDATE,
                       SYS_CONTEXT ('USERENV', 'CURRENT_USER'),
                       v_source_action,
                       v_source_rowid);
       ELSIF DELETING
       THEN
          INSERT INTO audit_table (col1,
                                   col2,
                                   col3,
                                   cre_date,
                                   cre_user,
                                   source_action,
                                   source_rowid)
               VALUES (:OLD.col1,
                       :OLD.col2,
                       :OLD.col3,
                       SYSDATE,
                       SYS_CONTEXT ('USERENV', 'CURRENT_USER'),
                       v_source_action,
                       v_source_rowid);
       END IF;
    END;
    /

如果我的理解有误,请纠正。谢谢

于 2013-03-26T12:56:42.340 回答
0

您想对触发器使用referencing子句。官方图在这里,但我发现这个页面解释得更好一些。

基本上,您可以这样创建触发器:

CREATE OR REPlACE TRIGGER trigger_name
AFTER DELETE OR INSERT OR UPDATE
ON table_name
REFERENCING OLD AS oldAlias AND NEW AS newAlias
...

现在您可以将触发前值和触发后值引用为:oldAlias.column_name:newAlias.column_name

例如,这将检查 person_type 值是否从 1 更新为 2:

IF :oldAlias.personnel_type = 1 AND :newAlias.personnel_type = 2 THEN 
  -- do something
END IF ;

据我所知,听起来您想创建一个触发器来监控多个表。Oracle 触发器不是这样工作的。您要监视的每个表都必须有自己的单独触发器。但是,您可以:

  • 从触发器调用一个过程/函数,将有问题的值传递给它(只要确保不要卡在递归/变异触发器中)
  • 使用自己的触发器创建单独的审计表。当您的源表更新时,您将更改/数据(例如表名或列)推送到审计表。然后审计表的触发器可以按照您的意愿处理。
于 2013-03-26T12:56:36.687 回答