在表上创建复杂触发器

Posted

技术标签:

【中文标题】在表上创建复杂触发器【英文标题】:create complex trigger on table 【发布时间】:2012-07-18 20:34:16 【问题描述】:

我有一个表格参与者,其结构如下所示:

Pid    number        
name   varchar2(20)    
version  number

每当我在 participants 表中插入任何记录时,版本 =1 都会被填充。

例如,如果我插入了 pid=1 ,name='Gaurav' 然后用 version =1 记录会被填充到 participants table 中。

现在我的issueupdateparticipants 表上,

    假设我正在为参与者表中的 pid=1 更新 name ='Niharika',然后需要在同一个表上创建一个 pid=1、name='Niharika' 和版本 =2 的新记录。 我再次在参与者表中更新 name='Rohan' for pid='1' 需要创建一个 pid=1、name='Rohan' 和 version=3 的新记录。

我怎样才能做到这一点,显然我需要为将要更新的 pid 获取 max(version)+1。

我可以使用视图来实现这一点,并使用而不是触发器插入视图,但我对我的解决方案不满意。

我还创建了复合触发器,即使这对我不起作用,因为在触发器内部我需要对该表使用插入语句,这会给我递归错误

【问题讨论】:

【参考方案1】:

你真的应该有两张桌子。使用您描述为“日志记录”表的结构制作一个。它将保留所有记录的历史记录。有另一个被认为是“当前”的表,它是相同的,但没有 version 列。然后,当“当前”表的记录发生插入/更新时,在日志表中有一个机制(例如触发器)SELECT FOR UPDATE max(version),添加一个,然后插入到日志表中。这样,您就不会遇到变异表错误或任何类似的奇怪问题。这种方式有一些序列化,但它最接近你想要做的。

【讨论】:

【参考方案2】:

通常不推荐,但无论如何您都可以这样做,而无需其他额外的日志记录表-

CREATE or REPLACE
TRIGGER part_upd
 AFTER UPDATE of name
 ON participants
 FOR EACH ROW
DECLARE
  retval BOOLEAN;
BEGIN

   retval := insert_row(:old.pid,:new.name);

END part_upd;

函数-

CREATE or REPLACE 
FUNCTION insert_row (pid1 number, name1 varchar2)
RETURN boolean
IS
    PRAGMA autonomous_transaction;
BEGIN
     INSERT INTO participants
     SELECT pid1, name1, max(vers)+1
       FROM participants
      WHERE pid = pid1;         

     COMMIT; 

     RETURN true;
END;

您必须通过添加日志记录和异常处理来适当地微调触发器和函数。阅读有关autonomous_transaction 的更多信息。

【讨论】:

-1 如果触发语句回滚,这将导致插入虚假行。 这就是第一个词是“通常不推荐”的原因,使用“autonomous_transaction”总是有一个警告 “通常不推荐”意味着您可能“有时推荐”这种方法。我不同意。

以上是关于在表上创建复杂触发器的主要内容,如果未能解决你的问题,请参考以下文章

触发器---存储过程---存储函数

在具有聚集列存储索引的表上创建触发器 - 错误

MySQL触发器trigger的使用

在使用 Entity Framework 数据库优先在表上插入行之前,如何从 PL/SQL 执行触发器?

由于“指定的事件类型在指定的目标对象上无效”,无法在 SQL 表上创建触发器。

用于在表上自动生成 ID 的序列和触发 PL/SQL 脚本