快速提问。 所以我有一个名为PARENT的表和一个名为CHILD的表,假设它们处于父子关系中。删除其他表的数据时是否可以删除其中一个?
我最初的尝试是使用级联删除来删除CHILD记录删除PARENT记录时。 同时我在删除CHILD的记录时使用触发器删除PARENT记录。(条件是在CHILD上删除,触发后)
结果是ORA-04091:表格是变异的。 它造成了一种僵局。
父表已删除 - >级联删除子 - >触发器触发删除父级, 此时,PARENT中已删除的记录未提交,因此我们处于不稳定状态。
是否有可能以这种方式关联父和子表的记录,如果一个被删除,另一个也被杀死了?我们假设这个CHILD表是唯一的子节点,CHILD中具有外键的列与PARENT中的引用列具有1对1的关系。
编辑:我来过oracle文档进行复合触发,这是一个有趣的读物。如果有效,我会更新它。
答案 0 :(得分:2)
这种级联通常没有意义。 创建子项时父项必须存在。所以常识不应仅仅因为没有孩子而删除父母。
如果您只使用1对1的关系,则只需要更改程序逻辑,以便在需要删除子项时仅删除父记录。
然而,如果你真的需要这个东西。我称之为LONELY_PARENT_CLEANUP程序。现在,当我们有名称和意义时,我们只需要执行它。 因为我们无法从触发器(变异表!)运行它,所以我们应该进行清理工作。我们可以通过触发器或某些时间表启动此作业。在清除父母之前可能会有轻微的延迟。
假设我们的TEST_PARENT
表包含列(id)
和TEST_CHILD
表,列(id, parent_id)
。我们用DELETE CASCADE创建了FK
创建删除父项的过程。我建议我们尽快删除父母。
CREATE OR REPLACE PROCEDURE DELETE_LONELY_PARENT (p_id IN NUMBER) AS
BEGIN
DELETE FROM test_parent WHERE id = p_id;
COMMIT;
END DELETE_LONELY_PARENT;
现在我们需要TEST_CHILD
表上的triger:
CREATE OR REPLACE TRIGGER DELETE#PARENT#TRG
BEFORE DELETE ON TEST_CHILD FOR EACH ROW
DECLARE
jobId NUMBER;
BEGIN
dbms_job.submit(
job => jobId,
what => 'BEGIN DELETE_LONELY_PARENT('|| :old.parent_id ||'); END;'
);
END;
现在,当您删除子记录时,特殊作业将开始删除父记录。由于其不同的交易,不再存在变异表问题。