2009-08-05 5 views
4

제약 조건이있는 Oracle에서 일대일 관계를 완전히 모델링 할 수 있습니까? 즉, PARENT 엔티티는 항상 하위 엔티티의 n-CHILDREN을 가지며 각 자식은 오직 하나의 부모 만 갖습니다.일대일 관계 모델링

n은 데이터베이스 상수가됩니다.

답변

5

이렇게하면 여러 세션이 업데이트를 수행하고 있어도 소리가 정확하고 정확합니다. 트리거를 사용하여이 작업을 시도하면 혼란에 빠지며 오라클의 선언적 제약은이를 표현할만큼 강력하지 않습니다.

  1. 가 그들을 함께 결합하고 그룹화하는 아이의 수를 계산보기 가입 구체화 된 만들기 부모와 아이 모두 테이블에 대한 구체화 된 뷰 로그를 생성 -이 다음과 같이

    그것은 수행 할 수 있습니다 부모가 이것은 FAST ON

  2. 가 자식 레코드의 카운트가 그런 다음 삽입/업데이트하는 일련의 작업을 수행 할 수 있습니다

"N"(데이터베이스 상수)와 동일해야한다는 가입 구체화 된 뷰에 제약을 넣어 COMMIT REFRESH해야합니다/delete 문. 확약하면 구체화 된 뷰가 새로 고쳐지며 조건이 충족되지 않으면 해당 시점에서 제한 조건 위반 오류가 발생합니다.

한계점은 저장소를 낭비하지 않도록 구체화 된보기 (HAVING 개수 (ChildId) <> 5)에 제약 조건을 만족하지 않는 행을 포함하는 것입니다.

1

나는 어떻게 보이지 않습니다. 그것은 "닭이나 계란이 먼저 왔을까?"라는 오래된 질문입니다. 자녀가 아직 추가되지 않은 경우 어떻게 부모를 제한 할 수 있으며 부모없이 자녀를 추가 할 수 있습니까?

"ValidParents"와 같은 새로운 테이블을 만들 수 있습니다.이 테이블에는 N 개의 자식이있는 상위 ID 만 있고 트리거와 동기화 상태를 유지합니다.

+0

우수한 점. – JohnFx

+4

지연 가능한 제약 조건. – cagcowboy

+1

트리거를 올바르게 사용하는 것은 매우 어렵습니다. 테이블 잠금을 사용하여 테이블에서 여러 개의 동시 트랜잭션에서 올바르게 작동하게해야합니다. 모든 거래는 서로 뒤쳐져야하며 잘못 처리됩니다. –

0

이것은 원하는 것이 아니지만 비슷한 것을하는 한 가지 방법이 있습니다.

일대는이 같은 것입니다에 대한 일반적인 배열 :

Primary Table: 
primary_id (PK) 
primary_stuff 

Secondary Table: 
secondary_id (PK) 
primary_id (FK) 
secondary_stuff 

대안 일 것이다 엄격한 일대일를 모델링하기 :

Primary Table: 
primary_id (PK) 
secondary_id (FK, non-null) 
primary_stuff 

Secondary Table: 
secondary_id (PK) 
secondary_stuff 

그것은 수 있습니다 약간 이상하지만 작동합니다. 이 변형은 고객에 대해 여러 개의 주소가 있지만 하나의 청구서 수신 주소와 같이 일대일로 구성된 일대 다수가있는 경우에 유용 할 수 있습니다.

+0

부모 행을 삽입하기 전에 고아 행을 삽입해야합니다. –

+0

맞습니다. 삽입이 트랜잭션에 있어야하는 이유입니다. –

3

earler "chicken + egg"포인트를 빌드하면 커밋 할 때까지 유효성을 검사 할 수없는 연기 가능한 제약 조건을 만들 수 있습니다. 이것들이 도움이 될 수 있습니까?

ALTER TABLE AGREEMENTS ADD CONSTRAINT name FOREIGN KEY (column) REFERENCES table (column) DEFERRABLE INITIALLY DEFERRED; 
0

닭고기 및 계란 문제의 대안은 INSERT ALL을 사용하는 것입니다. 이것은 단일 명령문이기 때문에 연기 가능한 외래 키 제약 조건의 필요성을 없애줍니다. 또한 종속 행의 정확한 수를 삽입하는 메커니즘을 제공합니다. 추가 제한 조건으로 인해 추가 행이 삽입되지 않습니다.그러나 우연한 행 삭제를 방지하기 위해 외래 키가있는 보조 테이블이 필요합니다. 이 예에서

N =

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> 

3. I의 용액을 고안하고 또한 유연성이 사소한 받아들이, 그러나 그래서 원래 요구이다. 또한 방탄에서 멀리 떨어져 있습니다 - 행을 CHILD_LOCK에서 삭제하고 하나 이상의 CHILD 레코드를 삭제할 수 있습니다.

0

보통 1 : M 관계로 테이블을 생성 한 다음 하위 테이블에는 부모에 대해 몇 명의 자식이 존재할 수 있는지를 결정하는 check 제약 조건이있는 계수 열과 부모 ID + 개수 열입니다. 예 :

CREATE TABLE Parent (PID NUMBER PRIMARY KEY); 

CREATE TABLE Child (
    PID NUMBER NOT NULL, 
    Count NUMBER(1) NOT NULL, 
    CONSTRAINT count_check CHECK (Count BETWEEN 1 AND 5), 
    CONSTRAINT parent_child_fk FOREIGN KEY (PID) REFERENCES Parent (PID), 
    CONSTRAINT count_unique UNIQUE (PID, Count)); 

유일하게 보장되지 않는 것은 각 부모에게는 적어도 5 명의 자녀가 있다는 것입니다. 이 문제를 해결하기 위해 WW가 제안한대로 제약 조건이 적용된 구체화 된보기를 만들거나 응용 프로그램에서 추가로 뭔가를 구축하십시오 (예 : "오류"보고서).

1

확인, 외부 키 및 고유성 제약 조건을 사용하여 구체화 된보기없이 각 부모가 0 또는 n 개의 자식을 정확히 갖도록하는 대안 솔루션이 있습니다. 이를 위해 어린이들에게 번호를 부여하고 다음 형제 자매의 번호를 포함하는 필드를 추가해야합니다.

create table Tree(
    id serial, 
    parent_id integer not null references Tree(id), 
    child_nr integer check(child_nr between 1 and 5), 
    next_sibling_nr integer, 
    unique (parent_id, child_nr), 
    check(next_sibling_nr in (child_nr+1, child_nr-4)), 
    check(((parent_id is null) and (child_nr is null) and 
    (next_sibling_nr is null)) or ((parent_id is not null) 
    and (child_nr is not null) and (next_sibling_nr is not null))), 
    foreign key (parent_id, next_sibling_nr) references Tree(parent_id, child_nr), 
    primary key (id) 
); 

마지막 (긴) 제약 분야는 PARENT_ID child_nr 및 next_sibling_nr하도록 보장 확인 : 여기에 다른 DBS의 하나, PostgreSQL을 작동 N = 5에 대한 예는 유형 시리얼에게 아마 적응한다 모두 null 또는 모두 null가 아니다. 유일성 제약과 child_nr 필드에 대한 검사는 부모가 최대 5 명의 자식을 갖도록주의를 기울입니다. 쌍의 다른 점검 제한 조건과 외부 키 제한 조건 (parent_id, next_sibling_nr)은 5 개 미만의 하위가 있음을 보장합니다.

명령으로 자동으로 생성 된 ID 1 루트를 삽입 한 후

insert into Tree (parent_id) 
    values (null); 

한 5의 팩에 항상 자녀를 추가 할 수 있습니다 :이 솔루션은 비슷한에 대한 답변에서 파생

insert into Tree (parent_id, child_nr, next_sibling_nr) 
    values (1, 1, 2), 
     (1, 2, 3), 
     (1, 3, 4), 
     (1, 4, 5), 
     (1, 5, 1); 

을 질문 나는 몇 주에 ago에게 물었다.

+0

나는 다른 사람들이 부모와 아이들이 다른 테이블에 있다는 것을 이해하는 것을 보았다. 반면에 나는 그들이 같은 테이블에 있다고 생각했다. 내 대답을 두 테이블에 적용하는 것은 어렵지 않습니다. –