2010-08-09 87 views
2

我正在开发一个系统来跟踪项目的历史。有3个主表:项目,任务和客户,然后是3个历史表。我在项目表上有以下触发器。oracle和创建历史

CREATE OR REPLACE TRIGGER mySchema.trg_projectHistory 
BEFORE UPDATE OR DELETE 
ON mySchema.projects REFERENCING NEW AS New OLD AS Old 
FOR EACH ROW 
declare tmpVersion number; 
BEGIN 
    select myPackage.GETPROJECTVERSION(:OLD.project_ID) into tmpVersion from dual; 

    INSERT INTO mySchema.projectHistiry 
    (project_ID, ..., version) 
    VALUES 
    (:OLD.project_ID, 
    ... 
    tmpVersion 
    ); 

EXCEPTION 
WHEN OTHERS THEN 
    -- Consider logging the error and then re-raise 
    RAISE; 
END ; 
/

我有三个触发器为我的每个表(项目,任务,客户端)。

以下是挑战:并非所有事情都在同一时间发生变化。例如,有人可以更新某个任务的成本。在这种情况下,只有一个触发器触发,并且我有一个插入。即使在项目和客户表中没有任何更改,我想一次将一条记录插入到3个历史记录表中。

另外,如果有人更改项目的end_date,成本,并说选择另一个客户端会怎么样。现在,我有三个触发器同时触发。只有在这种情况下,我才会在我的三张历史记录表中插入一条记录。 (我想要的)

如果我修改触发器插入到第一个示例的3个表中,那么当第二个示例发生时,我将有9个插入。

不太清楚如何解决这个问题。任何帮助?

回答

0

从您的描述中可以看出,一旦任何原始行发生更改,您将捕获每个历史记录行的生效日期和结束日期。

例如, Project_hist表将具有eff_date和exp_date,它具有给定项目的开始日期和结束日期。项目表只会有一个生效日期。 (因为它是活跃的项目)。

我不明白为什么要在只更新一个表值时为所有三个历史记录表插入行。您可以根据自己当前的逻辑,根据需要获取详细信息(截至给定日期)。 (在已更新的表格的历史记录表格中插入旧行)。

+0

是真实的,但是我面临的另一个挑战是现在有任务历史记录,但没有项目/客户历史记录。我必须找出一个连接:如果x_history中没有任何内容,请从x获取它。 – CFNinja 2010-08-09 19:10:56

+0

那么,在这种情况下,你可以尝试在历史表中同时使用活动版本和非活动版本吗?这种方法的缺点是,在每次更新操作表中的当前记录后,您需要更新历史记录中的最新记录,然后插入新记录。 – 2010-08-09 19:41:03

+0

历史记录表仅包含非活动版本。对任何主表的任何更新/删除都将创建不活动的历史版本。 我如何做后者? 如果x_history中没有任何内容,请从x获取它。 – CFNinja 2010-08-09 20:45:56

2

对我来说,听起来好像你想要对任何一个表进行更改时创建的三个表的事务级快照。

在三个表中的每一个上都有一个行级别的触发器,它们调用带有项目ID和可选的客户机/任务ID的单个打包过程。

打包过程会在所有三个历史记录表中插入相关的项目,客户端和任务,其中没有该密钥和事务的历史记录(即,您不需要重复项)。谈到后者,你有几个选择。你可以使用一个唯一的约束和一个BULK选择和插入与FORALL/SAVE EXCEPTIONS,DML错误记录(EXCEPTIONS INTO)或INSERT ... SELECT ... WHERE NOT EXISTS ...

你确实需要跟踪您的交易。我猜这是你用myPackage.GETPROJECTVERSION所做的。这里的技巧是只有当你有一个新的事务时才增加版本。如果当你得到一个新的版本号,你将它保存在一个pacakge级别变量中,你可以很容易地判断你的会话是否已经有一个版本号。

如果您的会话要运行多个事务,那么如果它是前一个事务的一部分,则需要“清除”会话级版本号。如果您获得DBMS_TRANSACTION.LOCAL_TRANSACTION_ID并将其存储在程序包/会话级别,则可以确定您是在新事务中还是在同一事务中。

+0

+1用于诊断问题背后的用例 – APC 2010-08-10 03:25:33

+0

我想你会想为同一事务中的后续更改执行“合并”。如果你使用'not exists',你最终会得到一个快照,其中包含对一个表的初始更改并忽略另外两个(以及对同一事务中第一个表的进一步更改)。 – Allan 2010-08-10 21:09:33

0

替代答案。 查看Total Recall/Flashback Archive 您可以将保留时间设置为10年,并使用简单的AS OF TIMESTAMP来获取任何特定时间戳的数据。

虽然不确定。每天或每周保留一次可能更容易,然后使用VERSIONS BETWEEN语法挑选出较早版本的单独计划作业,并将它们存储在历史记录表中。

+0

如果这些牌照有钱的话,Total Recall绝对是最优雅的解决方案。 – APC 2010-08-10 03:22:21