このようなシナリオでの一般的なアドバイスは、遅延可能な制約を採用することです。ただし、これらの状況はほとんどの場合、アプリケーション ロジックまたはデータ モデルの障害であると思います。たとえば、子レコードと親レコードを同じトランザクションに挿入すると、2 つのステートメントとして実行すると問題が発生する可能性があります。
私のテストデータ:
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>
親レコードの主キーを更新したいのですが、子レコードが存在するために更新できません。また、親キーがないため、子レコードを更新できません。キャッチ-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 ステートメントの構文は少し不格好ですが、通常は不格好です。ポイントは、主キー列を頻繁に更新する必要がないことです。実際、不変性は「主キー性」の特徴の 1 つであるため、それらを更新する必要はまったくありません。そうする必要があるのは、データモデルの失敗です。このような失敗を回避する 1 つの方法は、合成 (代理) 主キーを使用し、一意の制約を使用して自然 (別名ビジネス) キーの一意性を単純に強制することです。
では、なぜオラクルは遅延可能な制約を提供するのでしょうか? これらは、データの移行や一括データのアップロードを行う際に役立ちます。これにより、テーブルをステージングせずにデータベース内のデータをクレンジングできます。通常のアプリケーション タスクには必要ありません。