如何删除具有双向依赖关系的行?

时间:2011-10-05 18:29:17

标签: oracle foreign-keys constraints delete-row

我正在使用Oracle 10g Express并尝试从具有双向约束的表中删除记录。我试图解开数百个通过Hibernate生成的表和依赖项(此时无法更改),但这里有一个简化示例:

create table TableA (id number(19,0) not null, ..., rTableA_id number(19,0), primary key (id));
create table TableB (id number(19,0) not null, ..., rTableB_id number(19,0), primary key (id));

alter table TableA add constraint FKA1 foreign key (rTableA_id) references TableB;
alter table TableB add constraint FKB1 foreign key (rTableB_id) references TableA;

尝试从任一表中删除条目将返回以下内容:
编辑:在我的情况下,这种情况发生在前缀为 SYS _

的外键上
ORA-02292: integrity constraint (XXX.FKA1) violated - child record found

我也试图禁用约束,但所有尝试都是徒劳的:

ORA-02297: cannot disable constraint (XXX.FKA1) - dependencies exist

3 个答案:

答案 0 :(得分:5)

我不得不想知道你的数据首先处于这种状态,因为你的外键是not null。如果两个表都是空的,那么你就永远无法在任何一个表中插入一行。

暂时忽略这一点,重新创建场景,我没有问题禁用约束:

CREATE TABLE tablea(id NUMBER(19, 0) NOT NULL, 
                    rtablea_id NUMBER(19, 0) NOT NULL, 
                    PRIMARY KEY(id))
/

CREATE TABLE tableb(id NUMBER(19, 0) NOT NULL, 
                    rtableb_id NUMBER(19, 0) NOT NULL, 
                    PRIMARY KEY(id))
/

INSERT INTO tablea
VALUES     (1, 2)
/

INSERT INTO tableb
VALUES     (2, 1)
/

ALTER TABLE tablea ADD CONSTRAINT fka1 
                       FOREIGN KEY (rtablea_id)  
                       REFERENCES tableb
/
ALTER TABLE tableb ADD CONSTRAINT fkb1  
                       FOREIGN KEY (rtableb_id)  
                       REFERENCES tablea
/
ALTER TABLE tablea MODIFY CONSTRAINT fka1 DISABLE
/
ALTER TABLE tableb MODIFY CONSTRAINT fkb1 DISABLE
/
delete tablea
/
delete tableb
/
commit
/

结果:

Table created.
Table created.
1 row created.
1 row created.
Table altered.
Table altered.
Table altered.
Table altered.
1 row deleted.
1 row deleted.
Commit complete.

我不确定在尝试禁用外键时如何收到ORA-02297错误。当禁用外键所依赖的主键或唯一键时,通常会看到该错误。

我怀疑你真正想做的是将约束设置为initially deferred。这将允许您单独执行对每个表的插入和删除,只要在提交事务之前更新或删除相应的行:

CREATE TABLE tablea(id NUMBER(19, 0) NOT NULL,  
                    rtablea_id NUMBER(19, 0) NOT NULL,  
                    PRIMARY KEY(id))
/

CREATE TABLE tableb(id NUMBER(19, 0) NOT NULL,  
                    rtableb_id NUMBER(19, 0) NOT NULL,  
                    PRIMARY KEY(id))
/

ALTER TABLE tablea ADD CONSTRAINT fka1 
                       FOREIGN KEY (rtablea_id) 
                       REFERENCES tableb 
                       INITIALLY DEFERRED
/
ALTER TABLE tableb ADD CONSTRAINT fkb1 
                       FOREIGN KEY (rtableb_id) 
                       REFERENCES tablea 
                       INITIALLY DEFERRED
/

INSERT INTO tablea
VALUES     (1, 2)
/

INSERT INTO tableb
VALUES     (2, 1)
/

INSERT INTO tableb
VALUES     (3, 1)
/

COMMIT
/

DELETE tableb
WHERE  id = 2
/

UPDATE tablea
SET    rtablea_id   = 3
WHERE  id = 1
/

COMMIT
/

结果:

Table created.
Table created.
Table altered.
Table altered.
1 row created.
1 row created.
1 row created.
Commit complete.
1 row deleted.
1 row updated.
Commit complete.

答案 1 :(得分:3)

你确定不能告诉Hibernate创建可延迟的约束吗?如果DDL不使用DEFERRABLE关键字,则默认情况下约束将不可延迟。这意味着您将无法删除数据。如果您有一个包含循环引用的模式,那么您总是希望声明外键约束是可延迟的。

您可以删除约束,删除数据,然后重新创建约束(使用Hibernate的DDL或在末尾添加INITIALLY DEFERRED DEFERRABLE子句)。但是,如果您以任何频率从任一表中删除数据,那将是一个巨大的痛苦。如果新的A行想要引用您正在创建的新B行,您也会在插入新数据时遇到问题。

答案 2 :(得分:1)

我无法添加INITIALLY DEFERRED,因为数据库(以及底层的Hibernate脚本)已经存在。对于新系统,这可能是一个选项,但是,有许多工具(我只知道几个)依赖于当前形式的数据库而且我太害怕任何意外的副作用,只需添加此参数即可700桌。

因此,我使用了以下解决方案:

alter table TableA MODIFY CONSTRAINT FKA1 DISABLE;
alter table TableB MODIFY CONSTRAINT FKB1 DISABLE;

delete from TableA where id = 1;
delete from TableB where id = 2;

alter table TableA MODIFY CONSTRAINT FKA1 ENABLE;
alter table TableB MODIFY CONSTRAINT FKB1 ENABLE;