IS-A 관계를 데이터베이스에 어떻게 매핑합니까?


26

다음을 고려하세요:

entity User
{
    autoincrement uid;
    string(20) name;
    int privilegeLevel;
}

entity DirectLoginUser
{
    inherits User;
    string(20) username;
    string(16) passwordHash;
}

entity OpenIdUser
{
    inherits User;
    //Whatever attributes OpenID needs... I don't know; this is hypothetical
}

다른 종류의 사용자 (직접 로그인 사용자 및 OpenID 사용자)는 IS-A 관계를 표시합니다. 즉, 두 유형의 사용자는 모두 사용자입니다. 이제 RDBMS에서이를 나타낼 수있는 몇 가지 방법이 있습니다.

방법 하나

CREATE TABLE Users
(
    uid INTEGER AUTO_INCREMENT NOT NULL,
    name VARCHAR(20) NOT NULL,
    privlegeLevel INTEGER NOT NULL,
    type ENUM("DirectLogin", "OpenID") NOT NULL,
    username VARCHAR(20) NULL,
    passwordHash VARCHAR(20) NULL,
    //OpenID Attributes
    PRIMARY_KEY(uid)
)

두 번째 방법

CREATE TABLE Users
(
    uid INTEGER AUTO_INCREMENT NOT NULL,
    name VARCHAR(20) NOT NULL,
    privilegeLevel INTEGER NOT NULL,
    type ENUM("DirectLogin", "OpenID") NOT NULL,
    PRIMARY_KEY(uid)
)

CREATE TABLE DirectLogins
(
    uid INTEGER NOT_NULL,
    username VARCHAR(20) NOT NULL,
    passwordHash VARCHAR(20) NOT NULL,
    PRIMARY_KEY(uid),
    FORIGEN_KEY (uid) REFERENCES Users.uid
)

CREATE TABLE OpenIDLogins
(
    uid INTEGER NOT_NULL,
    // ...
    PRIMARY_KEY(uid),
    FORIGEN_KEY (uid) REFERENCES Users.uid
)

세번째 방법

CREATE TABLE DirectLoginUsers
(
    uid INTEGER AUTO_INCREMENT NOT NULL,
    name VARCHAR(20) NOT NULL,
    privlegeLevel INTEGER NOT NULL,
    username VARCHAR(20) NOT NULL,
    passwordHash VARCHAR(20) NOT NULL,
    PRIMARY_KEY(uid)
)

CREATE TABLE OpenIDUsers
(
    uid INTEGER AUTO_INCREMENT NOT NULL,
    name VARCHAR(20) NOT NULL,
    privlegeLevel INTEGER NOT NULL,
    //OpenID Attributes
    PRIMARY_KEY(uid)
)

데이터베이스의 다른 곳에서 사용자에 대해 간단한 조인을 수행 할 수 없기 때문에 세 번째 방법이 잘못된 방법이라고 거의 확신합니다.

내 실제 예는 다른 로그인 예를 가진 사용자가 아닙니다. 일반적인 경우에이 관계를 모델링하는 방법에 관심이 있습니다.


Joel Brown의 의견에 제안 된 접근법을 포함하도록 답변을 편집했습니다. 당신을 위해 작동합니다. 더 많은 제안을 찾고 있다면 MySQL 관련 답변을 찾고 있음을 나타 내기 위해 질문에 태그를 다시 지정합니다.
Nick Chammas

실제로 나머지 데이터베이스에서 관계가 사용되는 방식에 따라 달라집니다. 자식 엔터티와 관련된 관계는 해당 테이블에만 외래 키가 필요하며 해킹없이 단일 통합 테이블에 매핑하는 것을 금지합니다.
beldaz

PostgreSQL과 같은 객체 관계형 데이터베이스에는 실제로 네 번째 방법이 있습니다. 다른 테이블에서 INHERITS 테이블을 선언 할 수 있습니다. postgresql.org/docs/current/static/tutorial-inheritance.html
MarkusSchaber

답변:


16

방법 2는 올바른 방법입니다.

기본 클래스는 테이블을 가져온 다음 하위 클래스는 추가 필드와 기본 테이블에 대한 외래 키 참조만으로 자체 테이블을 가져옵니다.

Joel 이이 답변에 대한 의견에서 제안한 것처럼 사용자는 키를 입력하는 각 하위 유형 테이블에 유형 열을 추가하여 사용자가 직접 로그인 또는 OpenID 로그인을 가질 수 있지만 둘 다 (또는 둘다는 아님)를 보장 할 수 있습니다. 루트 테이블에. 각 하위 유형 테이블의 유형 열은 해당 테이블의 유형을 나타내는 단일 값을 갖도록 제한됩니다. 이 열은 루트 테이블에 외래 키가 지정되므로 한 번에 하나의 하위 유형 행만 동일한 루트 행에 연결할 수 있습니다.

예를 들어 MySQL DDL은 다음과 같습니다.

CREATE TABLE Users
(
      uid               INTEGER AUTO_INCREMENT NOT NULL
    , type              ENUM("DirectLogin", "OpenID") NOT NULL
    // ...

    , PRIMARY_KEY(uid)
);

CREATE TABLE DirectLogins
(
      uid               INTEGER NOT_NULL
    , type              ENUM("DirectLogin") NOT NULL
    // ...

    , PRIMARY_KEY(uid)
    , FORIGEN_KEY (uid, type) REFERENCES Users (uid, type)
);

CREATE TABLE OpenIDLogins
(
      uid               INTEGER NOT_NULL
    , type              ENUM("OpenID") NOT NULL
    // ...

    PRIMARY_KEY(uid),
    FORIGEN_KEY (uid, type) REFERENCES Users (uid, type)
);

(다른 플랫폼에서는 CHECK대신에 제약 조건을 사용합니다 ENUM.) MySQL 복합 외래 키를 지원 하므로이 기능 이 효과적입니다.

NULL사용 가능한 열의 공간을 낭비하고 있지만 사용 방법은 사용자 유형에 따라 다르지만 하나는 유효합니다 . 저장할 유형의 사용자 유형을 확장하도록 선택하고 해당 유형에 추가 열이 필요하지 않은 경우 도메인을 확장 ENUM하고 동일한 테이블을 사용할 수 있다는 장점이 있습니다 .

세 번째 방법은 사용자를 참조하는 모든 쿼리가 두 테이블을 모두 확인하도록합니다. 또한 외래 키를 통해 단일 사용자 테이블을 참조 할 수 없습니다.


1
방법 2를 사용하면 다른 두 테이블에 정확히 하나의 해당 행이 있다는 것을 강요 할 수있는 방법이 없다는 것을 어떻게 처리합니까?
Billy ONeal

2
@ 빌리-좋은 반대. 사용자가 둘 중 하나만 가질 수있는 경우 proc 계층 또는 트리거를 통해이를 시행 할 수 있습니다. 이 제약 조건을 적용하는 DDL 수준의 방법이 있는지 궁금합니다. (아아는 인덱싱 된 뷰는 허용하지 않습니다 UNION , 또는 나는에 대한 고유 인덱스와 인덱스 된 뷰 제안했을 UNION ALLuid두 테이블에서합니다.)
닉 Chammas에게

물론 이는 RDBMS가 처음에 인덱싱 된 뷰를 지원한다고 가정합니다.
Billy ONeal

1
이러한 종류의 교차 테이블 제약 조건을 구현하는 편리한 방법은 수퍼 유형 테이블에 분할 특성을 포함시키는 것입니다. 그런 다음 각 하위 유형이 적절한 파티셔닝 속성 값을 가진 수퍼 유형에만 관련되어 있는지 확인할 수 있습니다. 따라서 하나 이상의 다른 하위 유형 테이블을보고 충돌 테스트를 수행하지 않아도됩니다.
Joel Brown

1
@Joel-예를 들어 제약 조건을 type통해 CHECK제한된 하나의 값 (해당 테이블 유형)을 갖도록 제한되는 각 하위 유형 테이블에 열을 추가합니다 . 그런 다음 수퍼 테이블의 하위 테이블 외래 키를 uid및의 복합 키로 type만듭니다. 독창적입니다.
Nick Chammas

5

그들은 지명 될 것입니다

  1. 단일 테이블 상속
  2. 클래스 테이블 상속
  3. 콘크리트 테이블 상속 .

모두 합법적 인 용도로 사용되며 일부 라이브러리에서 지원됩니다. 가장 적합한 것을 찾아야합니다.

테이블이 여러 개인 경우 데이터 관리가 응용 프로그램 코드에 더 많이 사용되지만 사용되지 않은 공간은 줄어 듭니다.


2
"공유 기본 키"라는 추가 기술이 있습니다. 이 기술에서 서브 클래스 테이블에는 독립적으로 지정된 기본 키 ID가 없습니다. 대신 서브 클래스 테이블의 PK는 수퍼 클래스 테이블을 참조하는 FK입니다. 이는 주로 IS-A 관계의 일대일 특성을 강화한다는 몇 가지 이점을 제공합니다. 이 기술은 클래스 테이블 상속에 추가됩니다.
Walter Mitty
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.