我正在使用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
答案 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;