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

发布于 2024-12-08 14:54:40 字数 792 浏览 1 评论 0原文

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

I'm using Oracle 10g Express and trying to delete records from tables with bi-directional constraints. I'm trying to un-thread hundreds of tables and dependencies generated via Hibernate (which can't be changed at this point), but here is an extremely simplified example:

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;

Trying to delete entries from either table returns the following:
EDIT: This happens in my case with foreign keys prefixed with SYS_

ORA-02292: integrity constraint (XXX.FKA1) violated - child record found

I've also tried to disable constraints but all attempts are futile:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

新一帅帅 2024-12-15 14:54:40

我想知道你的数据首先是如何进入这种状态的,因为你的外键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 错误。当禁用外键依赖的主键或唯一键时,通常会出现该错误。

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

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.

I have to wonder how your data got in this state in the first place, since your foreign keys are not null. If both tables were empty to start with, you'd never be able to insert a row into either table.

Ignoring that for a moment, recreating your scenario, I have no problem disabling the constraints:

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
/

Result:

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.

I'm not sure how you'd get a ORA-02297 error when attempting to disable a foreign key. That error is typically seen when disabling a primary or unique key that a foreign key relies upon.

I suspect what you really want to do is set the constraints to initially deferred. This would allow you to perform inserts and deletes to each table individually, as long as the corresponding row was updated or deleted before the transaction is commited:

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
/

Result:

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.
带刺的爱情 2024-12-15 14:54:40

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

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

Are you sure that Hibernate cannot be told to create the constraints as deferrable? If the DDL doesn't use the DEFERRABLE keyword, the constraints will be non-deferrable by default. That is going to mean that you won't be able to delete the data. If you have a schema with circular references, you would always want to declare your foreign key constraints to be deferrable.

You could drop the constraints, delete the data, and then re-create the constraints (either using Hibernate's DDL or by adding the INITIALLY DEFERRED DEFERRABLE clause at the end). But that would be a major pain if you delete data from either table with any sort of frequency. You'll also tend to have problems inserting new data if the new A row wants to reference the new B row you're creating.

情独悲 2024-12-15 14:54:40

我无法添加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;

I was unable to add INITIALLY DEFERRED because the databases (as well as the underlying Hibernate scripts) already exist. For new systems, this would have been an option, however, there are many tools (of which I only know several) which rely on the Database in its current form and I was too afraid of any unintended side-effects by adding this parameter to 700 tables.

Therefore, I used the following solution:

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文