Общий совет для таких сценариев - использовать отсроченные ограничения .Тем не менее, я думаю, что эти ситуации почти всегда являются ошибкой логики приложения или модели данных.Например, вставка дочерней записи и родительской записи в одну и ту же транзакцию может стать проблемой, если мы выполним ее как два оператора:
Мои тестовые данные:
SQL> select * from t23 order by id, parent_id
2 /
ID PARENT_ID NAME
---------- ---------- ------------------------------
110 parent 1
111 parent 2
210 110 child 0
220 111 child 1
221 111 child 2
222 111 child 3
6 rows selected.
SQL>
Неправильный способделать вещи:
SQL> insert into t23 (id, parent_id, name) values (444, 333, 'new child')
2 /
insert into t23 (id, parent_id, name) values (444, 333, 'new child')
*
ERROR at line 1:
ORA-02291: integrity constraint (APC.T23_T23_FK) violated - parent key not
found
SQL> insert into t23 (id, parent_id, name) values (333, null, 'new parent')
2 /
1 row created.
SQL>
Однако Oracle поддерживает многостоловой INSERT synatx, который позволяет нам вставлять родительские и дочерние записи в один оператор , что устраняет необходимость в отложенных ограничениях:
SQL> rollback
2 /
Rollback complete.
SQL> insert all
2 into t23 (id, parent_id, name)
3 values (child_id, parent_id, child_name)
4 into t23 (id, name)
5 values (parent_id, parent_name)
6 select 333 as parent_id
7 , 'new parent' as parent_name
8 , 444 as child_id
9 , 'new child' as child_name
10 from dual
11 /
2 rows created.
SQL>
Ситуация, в которой вы находитесь, аналогична: вы хотите обновить первичный ключ родительской записи, но не можете из-за существования дочерних записей: и вы не можете обновить дочерний элементзаписи, потому что нет родительского ключа.Catch-22:
SQL> update t23
2 set id = 555
3 where id = 111
4 /
update t23
*
ERROR at line 1:
ORA-02292: integrity constraint (APC.T23_T23_FK) violated - child record found
SQL> update t23
2 set parent_id = 555
3 where parent_id = 111
4 /
update t23
*
ERROR at line 1:
ORA-02291: integrity constraint (APC.T23_T23_FK) violated - parent key not
found
SQL>
Еще раз решение состоит в том, чтобы сделать это в одном выражении:
SQL> update t23
2 set id = decode(id, 111, 555, id)
3 , parent_id = decode(parent_id, 111, 555, parent_id)
4 where id = 111
5 or parent_id = 111
6 /
4 rows updated.
SQL> select * from t23 order by id, parent_id
2 /
ID PARENT_ID NAME
---------- ---------- ------------------------------
110 parent 1
210 110 child 0
220 555 child 1
221 555 child 2
222 555 child 3
333 new parent
444 333 new child
555 parent 2
8 rows selected.
SQL>
Синтаксис в выражении UPDATE немного неуклюж, но, как правило, кладжи.Дело в том, что нам не нужно обновлять столбцы первичного ключа очень часто.Действительно, поскольку неизменность является одной из характеристик «первичной ключности», нам вообще не нужно их обновлять.Это необходимо для сбоя модели данных.Один из способов избежать таких сбоев - использовать синтетический (суррогатный) первичный ключ и просто обеспечить уникальность естественного (бизнес-) ключа с помощью уникального ограничения.
Так почему же Oracle предлагает отложенные ограничения?Они полезны, когда мы проводим миграцию данных или массовую загрузку данных.Они позволяют нам очищать данные в базе данных без промежуточных таблиц.Нам действительно не нужны они для обычных прикладных задач.