0

我有十几个表,我想保留其中的更改历史记录。对于每一个,我都创建了第二个以 _HISTO 结尾的表,并添加了字段 modtime、action、user。

在我插入、修改或删除此表中的记录之前,我调用(从我的 delphi 应用程序)一个 oracle 过程,它将实际值复制到 histo 表中,然后执行操作。

我的程序通过 DBA_TAB_COLUMNS 生成一个动态 sql,然后执行生成的(插入 tablename_histo ( fields s ) select fields, sysdate, 'acition', userid from table_name

有人告诉我,我不能从触发器调用此过程,因为它必须选择触发触发器的表。这是真的 ?是否有可能实现我所需要的?

4

2 回答 2

2

假设您想使用触发器来维护历史记录(而不是在 Oracle 中跟踪历史数据的任何其他方法——Workspace Manager、Total Recall、Streams、Fine_Grained Auditing 等),您可以在触发器中使用动态 SQL。但是动态 SQL 遵循与静态 SQL 相同的规则。甚至行级触发器中的静态 SQL 通常也无法在不生成变异表异常的情况下查询定义触发器的表。

但是,您可以编写一些动态 SQL,首先使用相同的数据字典表生成触发器,而不是从触发器中调用动态 SQL。触发器本身将静态引用:new.column_name:old.column_name。当然,您必须编辑触发器或重新运行在添加新列时动态创建触发器的过程。但是,由于您大概需要将列添加到主表和历史表中,因此这通常没什么大不了的。

于 2012-09-25T18:46:52.797 回答
0

Oracle 不允许触发器对定义触发器的表执行 SELECT。如果你尝试它,你会得到可怕的“mutating table”错误(ORA-04091),虽然有一些方法可以解决这个错误,但它们会增加很多复杂性而没有什么价值。如果您真的想在每次更新表时构建一个动态查询(从性能的角度来看,IMO 这是一个坏主意 - 我发现元数据查询通常很慢,但是 YMMV)它最终应该看起来像

strAction := CASE
               WHEN INSERTING THEN 'INSERT'
               WHEN UPDATING THEN 'UPDATE'
               WHEN DELETING THEN 'DELETE'
             END;

INSERT INTO TABLENAME_HISTO
  (ACTIVITY_DATE, ACTION, MTC_USER,
   old_field1, new_field1, old_field2, new_field2)
VALUES
  (SYSDATE, strAction, USERID,
   :OLD.field1, :NEW.field1, :OLD.field2, :NEW.field2)

分享和享受。

于 2012-09-26T11:22:10.953 回答