특권 자녀와 일대 다 관계를 맺는 방법?


22

각 부모에 대해 1 명 또는 0 명의 자녀가 "좋아하는"것으로 표시되는 일대 다 관계를 원합니다. 그러나 모든 부모가 자녀를 갖지는 않습니다. (이 사이트에서 부모님을 질문으로 생각하고, 대답으로 아이들을, 대답으로 좋아하는 것을 생각하십시오.) 예를 들어,

TableA
    Id            INT PRIMARY KEY

TableB
    Id            INT PRIMARY KEY
    Parent        INT NOT NULL FOREIGN KEY REFERENCES TableA.Id

내가 보는 방식으로 TableA에 다음 열을 추가 할 수 있습니다.

    FavoriteChild INT NULL FOREIGN KEY REFERENCES TableB.Id

또는 다음 열을 TableB로 이동하십시오.

    IsFavorite    BIT NOT NULL

첫 번째 접근 방식의 문제점은 nullable 외래 키를 도입한다는 것입니다.이 키는 정규화 된 형식이 아닙니다. 두 번째 접근 방식의 문제점은 최대 한 명의 어린이가 가장 좋아하는 것을 보장하기 위해 더 많은 작업을 수행해야한다는 것입니다.

어떤 접근 방식을 결정하기 위해 어떤 기준을 사용해야합니까? 아니면 내가 고려하지 않은 다른 접근법이 있습니까?

SQL Server 2012를 사용하고 있습니다.

답변:


19

다른 방법 (Null이없고 FOREIGN KEY관계에 주기가없는 )은 "좋아하는 아이들"을 저장하는 세 번째 테이블을 만드는 것입니다. 대부분의 DBMS에서는에 대한 추가 UNIQUE제약 조건 이 필요합니다 TableB.

@Aaron은 위의 명명 규칙이 다소 번거롭고 오류가 발생할 수 있음을 식별하는 것이 더 빨랐습니다. Id테이블 전체에 열 이없고 열 (결합 된 열)이 표시되는 많은 테이블에서 동일한 이름을 갖는 경우 일반적으로 더 좋습니다 . 여기 이름이 바뀌 었습니다.

Parent
    ParentID        INT NOT NULL PRIMARY KEY

Child
    ChildID         INT NOT NULL PRIMARY KEY
    ParentID        INT NOT NULL FOREIGN KEY REFERENCES Parent (ParentID)
    UNIQUE (ParentID, ChildID)

FavoriteChild
    ParentID        INT NOT NULL PRIMARY KEY
    ChildID         INT NOT NULL 
    FOREIGN KEY (ParentID, ChildID) 
        REFERENCES Child (ParentID, ChildID)

사용중인 SQL-Server에는 IsFavorite언급 한 비트 열 옵션도 있습니다 . 필터링 된 고유 인덱스를 통해 부모 당 고유 한 선호하는 자식을 달성 할 수 있습니다.

Parent
    ParentID        INT NOT NULL PRIMARY KEY

Child
    ChildID         INT NOT NULL PRIMARY KEY
    ParentID        INT NOT NULL FOREIGN KEY REFERENCES Parent (ParentID)
    IsFavorite      BIT NOT NULL

CREATE UNIQUE INDEX is_FavoriteChild
  ON Child (ParentID)
  WHERE IsFavorite = 1 ;

그리고 적어도 SQL-Server에서는 옵션 1이 권장되지 않는 주된 이유는 외래 키 참조의 순환 경로 패턴에 몇 가지 문제가 있기 때문입니다.

아주 오래된 기사 읽기 : SQL By Design : Circular Reference

두 테이블에서 행을 삽입하거나 삭제할 때 "chicken-and-egg"문제가 발생합니다. 제약 조건을 위반하지 않고 어떤 테이블을 먼저 삽입해야합니까?

이를 해결하려면 최소한 하나의 열을 nullable로 정의해야합니다. (OK, 기술적으로 당신은 당신이 모든 열을 가질 수 필요가 없습니다로 NOT NULL하지만, 연기 제약을 구현 한 비슷한 질문에 어윈의 답변을 @ 참조하십시오 포스트 그레스 및 Oracle과 같은 DBMS,에 :. SQLAlchemy의 복잡한 외래 키 제약 조건 방법 이것은 Postgres에서 수행 할 수 있습니다). 그래도이 설정은 얇은 얼음 위에서 스케이트를 타는 느낌입니다.

SO에서 거의 동일한 질문도 확인하십시오 (그러나 MySQL의 경우) SQL에서 두 테이블이 서로 참조해도 괜찮습니까? 내 대답은 거의 같습니다. MySQL에는 부분 인덱스가 없으므로 nullable FK와 여분의 테이블 솔루션 만 실행할 수 있습니다.


9

우선 순위가 무엇인지에 따라 다릅니다. 일을 피하고 싶거나 가장 엄격한 정규화 규칙을 따르고 싶습니까?

개인적으로, 나는 IsFavorite아이 테이블에있는 것이 더 낫다고 생각하며 , 모든 부모를 위해 최대 한 명의 아이가 그 부모가 가장 좋아하는 일이되도록 기꺼이 일할 것입니다. 주된 이유는 널 입력 가능 외래 키와 관련이 없습니다. 나는 모든 외래 키가 양방향을 가리키는 것을 좋아하지 않습니다.

@ ypercube의 제안은 좋은 타협입니다.

제쳐두고, 제발, 제발, 같은 의미없는 열 이름으로 스키마를 흩 뜨리지 마십시오 Id. 오히려 Id스키마 전체에서 의미있는 방식으로 이름이 지정되는 것을 보게 될 것 입니다. 저자를 식별합니까? 알았어 AuthorID. 제품을 나타 냅니까? 좋아, ProductID. 직원입니까, 경우에 따라 관리자를 언급합니까? 좋아, EmployeeID그리고 ManagerID보다 나에게 더 이해 ID하고 Parent. 복잡한 조인 (또는 여기에 쿼리를 게시)을 작성하기 시작할 때 해당 조인을 리버스 엔지니어링하려고 할 때 약간의 저주를 느끼게 될 것입니다. a.Parent = b.ID... blecch 와 같은 열에 .


1

데이터는 자식 테이블에 속합니다. 하나의 레코드 만 즐겨 찾기 (또는 선호하는 주소)로 표시되도록 테이블에서 트리거로 올바르게 유지합니다.

그러나 별도의 테이블에 대한 @ypercube의 아이디어도 좋습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.