Как удалить строки с двунаправленными зависимостями?

Я использую 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

person glenneroo    schedule 05.10.2011    source источник


Ответы (3)


Я должен задаться вопросом, как ваши данные вообще оказались в этом состоянии, поскольку ваши внешние ключи 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.
person Allan    schedule 05.10.2011
comment
Виноват! Внешние ключи не нулевые. Мое лучшее предположение состоит в том, что ошибка ORA-02297 возникает из-за вложенности сотен таблиц через внешние ключи, которые я пытаюсь раскрутить. На самом деле теперь я вижу, что вызывающие проблемы внешние ключи начинаются с SYS_. - person glenneroo; 06.10.2011
comment
@glenneroo: ограничения, начинающиеся с SYS_, обычно являются первичными ключами, которые не были названы во время создания. Я не знаю ни одного способа создания внешних ключей с системным именем. Если это первичные ключи, вы можете добавить cascade в конец команды disable, чтобы одновременно отключить все зависимые внешние ключи. - person Allan; 06.10.2011
comment
Добавление cascade сработало, но я все еще не могу удалить некоторые таблицы из-за ошибок ORA-02292. Глядя на таблицу user_constraints, кажется, что некоторые ограничения все еще включены. Кроме того, я также не могу снова включить ограничения (после удаления строк) из-за ORA-02270: no matching unique or primary key for this column-list. Интересно, могу ли я просто удалить и заново создать ограничения? - person glenneroo; 06.10.2011

Вы уверены, что Hibernate нельзя сказать создать ограничения как отсроченные? Если в DDL не используется ключевое слово DEFERRABLE, ограничения по умолчанию не будут откладываться. Это будет означать, что вы не сможете удалить данные. Если у вас есть схема с циклическими ссылками, вы всегда хотели бы объявлять ограничения внешнего ключа отсроченными.

Вы можете удалить ограничения, удалить данные, а затем заново создать ограничения (либо с помощью Hibernate DDL, либо добавив в конце предложение INITIALLY DEFERRED DEFERRABLE). Но это было бы серьезной проблемой, если бы вы удаляли данные из любой таблицы с любой частотой. У вас также могут возникнуть проблемы со вставкой новых данных, если новая строка A хочет ссылаться на новую создаваемую вами строку B.

person Justin Cave    schedule 05.10.2011
comment
Я мог бы указать Hibernate, но это живая система, поэтому мне придется создать сценарий обновления, чтобы изменить внешние ключи, чтобы добавить ключевое слово, если это вообще возможно. Я думал об удалении/восстановлении ограничений, так как это не критическая по времени операция — в основном разработчики должны очищать поврежденные данные. - person glenneroo; 07.10.2011

Мне не удалось добавить 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;
person glenneroo    schedule 18.12.2013