在更新触发器之前执行时出现约束违规错误

时间:2013-12-02 10:54:35

标签: oracle triggers

我正在使用oracle提供的示例HR模式试验触发器。 我试图在使用触发器在DEPARTMENTS TABLE中更新或删除各自的部门ID时删除或更新所有员工。

这是代码:

create or replace trigger UPDATE_EMPLOYEES_DEPT_ID
before update or delete of DEPARTMENT_ID on DEPARTMENTS
for each row
begin
  if UPDATING then
   update EMPLOYEES set DEPARTMENT_ID = :new.DEPARTMENT_ID where DEPARTMENT_ID = :OLD.DEPARTMENT_ID;
  ELSIF DELETING then
   update employees set department_id = null where DEPARTMENT_ID = :OLD.DEPARTMENT_ID;
  end if;

end;

当我执行时:

UPDATE departments SET department_ID = 112 WHERE department_ID = 110;

它给了我约束违规错误。

Error report:
SQL Error: ORA-02292: integrity constraint (HR.JHIST_DEPT_FK) violated - child record found
02292. 00000 - "integrity constraint (%s.%s) violated - child record found"
*Cause:    attempted to delete a parent key value that had a foreign
       dependency.
*Action:   delete dependencies first then parent or disable constraint.

我哪里错了?是否在'BEFORE TRIGGER'之前检查了完整性约束?

3 个答案:

答案 0 :(得分:1)

更新主键是probably not a good idea.。如果你绝对必须这样做,我建议不要使用触发器。在触发器中使用业务规则往往会导致难以维护的应用程序,因为代码是隐藏/分段的,它使标准DML看起来像魔术(意外的副作用)。

尽管如此,在您的情况下,您的错误似乎来自另一个表中的外键(可能是JOB_HISTORY?),并且您的代码逻辑应该在大多数情况下都有效,前提是您更新了所有子记录所有引用表。

答案 1 :(得分:0)

实现你想要的东西是非常有问题的,但并非不可能。

这里的交易是你必须在将密钥设置为null之前处理任何可能的约束。

如果我们想要实现解决方案,我相信我们需要在这里使用一点动态SQL。

这是我快速调整的触发器的修改版本(注意:我还没有测试过):

create or replace trigger UPDATE_EMPLOYEES_DEPT_ID
before update or delete of DEPARTMENT_ID on DEPARTMENTS
 for each row
begin
  if UPDATING then
   update EMPLOYEES set DEPARTMENT_ID = :new.DEPARTMENT_ID where DEPARTMENT_ID = :OLD.DEPARTMENT_ID;
  elsif DELETING then
   for i in ( select CONSTRAINT_NAME from USER_CONSTRAINTS where CONSTRAINT_TYPE='R' and R_CONSTRAINT_NAME in (select CONSTRAINT_NAME from USER_CONSTRAINTS where CONSTRAINT_TYPE in ('P','U') and TABLE_NAME='EMPLOYEES') )
    loop
     for j in ( select TABLE_NAME, COLUMN_NAME from USER_CONS_COLUMNS where CONSTRAINT_NAME = i.CONSTRAINT_NAME )
      loop
       update j.TABLE_NAME set j.COLUMN_NAME = null where j.COLUMN_NAME = :OLD.DEPARTMENT_ID;
      end loop;
    end loop;
   update EMPLOYEES set DEPARTMENT_ID = null where DEPARTMENT_ID = :OLD.DEPARTMENT_ID;
  end if;
end;

让我解释一下有关删除的一些方法:

  • 首先,它会抓取所有引用表'EMPLOYEES'
  • 的外键
  • 然后,对于发现的每个外键,它抓取表引用的表名和列
  • 然后,对于每个表 - 列对,它将使与以下项匹配的字段的值为空:OLD.DEPARTMENT_ID
  • 最后,在处理完所有外键后,它会使您最初计划的EMPLOYEES表中的DEPARTMENT_ID为空。

由于我没有真正测试过这个,请告诉我这是否会导致任何问题。

答案 2 :(得分:0)

如果您想使用触发器,则可以删除约束

I mean, perform all the operation of update delete by trigger only. and remove the constraint.
but doing so is not a good practice. So be sure with whatever you want to do.