How to delete rows with bi-directional dependencies?

萝らか妹 提交于 2020-01-15 19:31:28

问题


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

回答1:


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.



回答2:


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.




回答3:


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;


来源:https://stackoverflow.com/questions/7665914/how-to-delete-rows-with-bi-directional-dependencies

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!