Eine alternative Lösung für das Problem Huhn und Ei ist INSERT ALL. Da es sich um eine einzelne Anweisung handelt, entfällt die Notwendigkeit für aufschiebbare Fremdschlüsseleinschränkungen. Es bietet auch einen Mechanismus zum Einfügen einer genauen Anzahl von abhängigen Zeilen. Zusätzliche Einschränkungen verhindern das Einfügen zusätzlicher Zeilen.Wir benötigen jedoch eine Untertabelle mit Fremdschlüsseln, um das versehentliche Löschen der Zeilen von Interesse zu verhindern.
In diesem Beispiel n = 3.
SQL> create table parent
2 (pk_col number not null
3 , col1 varchar2(20)
4 , constraint par_pk primary key (pk_col)
5 )
6/
Table created.
SQL>
SQL> create table child
2 (pk_col number not null
3 , seqno number(1,0) not null
4 , col2 date
5 , constraint ch_pk primary key
6 (pk_col, seqno)
7 , constraint ch_par_fk foreign key
8 (pk_col) references parent (pk_col)
9 , constraint ch_ck check (seqno between 1 and 3)
10 )
11/
Table created.
SQL>
SQL> create table child_lock
2 (pk_col_1 number not null
3 , seqno_1 number(1,0) not null
4 , pk_col_2 number not null
5 , seqno_2 number(1,0) not null
6 , pk_col_3 number not null
7 , seqno_3 number(1,0) not null
8 , constraint chlk_pk primary key
9 (pk_col_1, seqno_1, pk_col_2, seqno_2, pk_col_3, seqno_3)
10 , constraint chlk_par_1_fk foreign key
11 (pk_col_1, seqno_1) references child (pk_col, seqno)
12 , constraint chlk_par_2_fk foreign key
13 (pk_col_2, seqno_2) references child (pk_col, seqno)
14 , constraint chlk_par_3_fk foreign key
15 (pk_col_3, seqno_3) references child (pk_col, seqno)
16 )
17/
Table created.
SQL>
SQL> insert all
2 into parent values (pk_val, val_1)
3 into child values (pk_val, 1, sysdate)
4 into child values (pk_val, 2, sysdate+1)
5 into child values (pk_val, 3, sysdate+2)
6 into child_lock values (pk_val, 1, pk_val, 2, pk_val, 3)
7 select 999 as pk_val
8 , 'APPLE PIE' as val_1
9 from dual
10/
5 rows created.
SQL>
SQL> insert into child values (999, 4, sysdate+4)
2/
insert into child values (999, 4, sysdate+4)
*
ERROR at line 1:
ORA-02290: check constraint (APC.CH_CK) violated
SQL> insert into child values (999, 3, sysdate+4)
2/
insert into child values (999, 3, sysdate+4)
*
ERROR at line 1:
ORA-00001: unique constraint (APC.CH_PK) violated
SQL> insert into child values (999, 2.5, sysdate+4)
2/
insert into child values (999, 2.5, sysdate+4)
*
ERROR at line 1:
ORA-00001: unique constraint (APC.CH_PK) violated
SQL> delete from child
2/
delete from child
*
ERROR at line 1:
ORA-02292: integrity constraint (APC.CHLK_PAR_1_FK) violated - child record found
SQL>
Ich akzeptiere die Lösung ein wenig gekünstelt und auch unflexibel ist, aber dann ist so die ursprüngliche Anforderung. Es ist auch bei weitem nicht kugelsicher - lösche die Zeile von CHILD_LOCK und du kannst einen oder mehrere CHILD-Datensätze löschen.
Ausgezeichneter Punkt. – JohnFx
Verschiebbare Einschränkungen. – cagcowboy
Es ist sehr schwer, es mit Triggern richtig zu machen. Sie müssen Tabellensperren entfernen, damit sie unter mehreren gleichzeitigen Transaktionen in der Tabelle ordnungsgemäß funktionieren. Alle Transaktionen müssen aufeinander warten und es wird schlecht funktionieren. –