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 ALL의 uid두 테이블에서합니다.)
— 닉 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.