2015-11-06 50 views
1
  create or replace trigger UPDATE_HISTORY 
      BEFORE INSERT OR UPDATE ON MAIN_TABLE 
      FOR EACH ROW 
      BEGIN 

      IF UPDATING THEN 

      INSERT INTO HISTORY(
       ID, 
       STATUS_ID 
      ) 
      VALUES 
      (
       :OLD.ID, 
       :OLD.STATUS_ID 
      ); 

      ELSE 

      :NEW.id := id_seq.nextval; 

      INSERT INTO HISTORY(
       ID, 
       STATUS_ID 
      ) 
      VALUES 
      (
       :NEW.ID, 
       :NEW.STATUS_ID 
      ); 

      END IF; 

      END; 

时,我正在经历我在哪里能创造MAIN_TABLE一个新的记录时插入数据,但是当我来到这个表中更新记录它会引发背部和错误的问题可以插入。我正在使用序列为历史记录表创建一个新的ID。更新时,但不插入

我收到的错误是“违反 - 父键未找到”/“第21行ORA-04088:触发器执行期间出错”。

+1

主表或历史表上是否有任何约束(外键,主键)?这个错误似乎与此有关。 – Hawk

+0

MAIN_TABLE或HISTORY表上是否有外键? – Dijkgraaf

+0

您可以运行下面的查询,找出:'SELECT * FROM USER_CONS_COLUMNS 在表格名=“<你的表名>”;' – Hawk

回答

3

这里有,我认为会导致错误两种情况。

我认为你打的就是插入一个新行。您试图在之前将插入到主表中的历史记录表中插入到主表中。因此,外键约束被违反,因为没有父子记录供孩子参考。为了避免这种情况,您可以将约束设置为延迟,因此直到您提交后才会检查它;或者使用AFTER触发器插入历史记录表中。

另一个问题是如果更新更改了主表中的行的ID。触发器会插入历史记录;那么更新本身会失败,因为子记录存在旧ID值。这可能是期望的行为,因为您通常不希望人们修改PK值。

+0

我会同意第二个问题。但是第一个与OP提到的不矛盾? '我可以在MAIN_TABLE中创建新记录时插入数据,但是当我来更新此表中的记录时,它会返回并返回错误'。 – Hawk

+0

干杯队友,真的有帮助。 – user3423975

+0

我同意这是一个矛盾 - 但问题的标题与文本相矛盾,所以我不知道除了代码之外应该相信什么。 –

0

所以要根据您的评论ID is the PK of MAIN_TABLE and the FK of HISTORY: 而据referrential完整性规则:

外键是到Oracle数据库中实施参照完整性的一种方式。外键意味着一个表中的值也必须出现在另一个表中。

被引用的表称为父表,而具有外键的表称为子表。子表中的外键通常会引用父表中的主键。

在INSERT:您的触发器将插入新的ID(即插入MAIN_TABLE),成为历史表。所以在这里,FK(它是HISTORY中的ID)在MAIN_TABLE中有PK - 工作正常。

在更新:,但是,您的MAIN_TABLE中的ID已被替换为新的ID。但是你试图将旧的插入历史表(它已经在MAIN_TABLE中被替换)。所以这个FK不再出现在MAIN_TABLE中。这违反了你的参照完整性规则。


你有ID = 3行中MAIN_TABLE,你将其更新到ID = 5。更新时,触发器试图将ID = 3插入历史记录(:old.ID)。但3不MAIN_TABLE

SOLUTION
这一切都取决于你想实现的逻辑,什么是你想实现不复存在。如果要存储:old.ID,则可能需要删除此特定列上的FK约束。或者你可能想存储:old.ID花药柱及用途:new.ID为FK

阅读FK here

+0

显示的示例是一个BEFORE触发器;因此在执行触发器后主表的更改会发生。我想,你的回答对AFTER触发器更为正确。 –

+0

@DaveCosta你说得对,我被'我能够在MAIN_TABLE中创建新记录时插入数据,但是当我来更新此表中的记录时,它会返回并出错' – Hawk