IT박스

여러 테이블에 대한 외래 키

itboxs 2020. 8. 4. 07:40
반응형

여러 테이블에 대한 외래 키


데이터베이스에 관련 테이블이 3 개 있습니다.

CREATE TABLE dbo.Group
(
    ID int NOT NULL,
    Name varchar(50) NOT NULL
)  

CREATE TABLE dbo.User
(
    ID int NOT NULL,
    Name varchar(50) NOT NULL
)

CREATE TABLE dbo.Ticket
(
    ID int NOT NULL,
    Owner int NOT NULL,
    Subject varchar(50) NULL
)

사용자는 여러 그룹에 속합니다. 이것은 다 대 다 관계를 통해 이루어 지지만이 경우에는 관련이 없습니다. dbo.Ticket.Owner 필드를 통해 그룹이나 사용자가 티켓을 소유 할 수 있습니다.

가장 정확한 방법은 티켓과 선택적으로 사용자 또는 그룹 간의이 관계를 설명하는 방법은 무엇입니까 ?

티켓 테이블에 어떤 유형의 소유인지를 나타내는 플래그를 추가해야한다고 생각합니다.


"정확성"및 사용 편의성에 따라 다양한 옵션이 있습니다. 항상 그렇듯이 올바른 디자인은 필요에 따라 다릅니다.

  • Ticket에서 OwnedByUserId 및 OwnedByGroupId라는 두 개의 열을 만들고 각 테이블에 대해 nullable 외래 키를 가질 수 있습니다.

  • ticket : user 및 ticket : group 관계를 모두 사용할 수있는 M : M 참조 테이블을 작성할 수 있습니다. 아마도 앞으로 여러 사용자 나 그룹이 단일 티켓을 소유하도록 허용 하시겠습니까? 이 디자인에서는 단일 엔티티 만 티켓 소유 해야하는 것은 아닙니다.

  • 모든 사용자에 대한 기본 그룹을 생성 할 수 있으며 티켓을 실제 그룹 또는 사용자의 기본 그룹에서 소유 할 수 있습니다.

  • 또는 (내 선택) 사용자 및 그룹 모두의 기반으로 작동하고 해당 엔티티가 소유 한 티켓이있는 엔티티를 모델링하십시오.

게시 된 스키마를 사용하는 대략적인 예는 다음과 같습니다.

create table dbo.PartyType
(   
    PartyTypeId tinyint primary key,
    PartyTypeName varchar(10)
)

insert into dbo.PartyType
    values(1, 'User'), (2, 'Group');


create table dbo.Party
(
    PartyId int identity(1,1) primary key,
    PartyTypeId tinyint references dbo.PartyType(PartyTypeId),
    unique (PartyId, PartyTypeId)
)

CREATE TABLE dbo.[Group]
(
    ID int primary key,
    Name varchar(50) NOT NULL,
    PartyTypeId as cast(2 as tinyint) persisted,
    foreign key (ID, PartyTypeId) references Party(PartyId, PartyTypeID)
)  

CREATE TABLE dbo.[User]
(
    ID int primary key,
    Name varchar(50) NOT NULL,
    PartyTypeId as cast(1 as tinyint) persisted,
    foreign key (ID, PartyTypeId) references Party(PartyID, PartyTypeID)
)

CREATE TABLE dbo.Ticket
(
    ID int primary key,
    [Owner] int NOT NULL references dbo.Party(PartyId),
    [Subject] varchar(50) NULL
)

@Nathan Skerl 의 목록 에서 첫 번째 옵션은 한 번 작업했던 프로젝트에서 구현 된 것입니다. 여기서 세 테이블간에 유사한 관계가 설정되었습니다. (그들 중 하나는 한 번에 하나씩 두 개의 다른 참조했습니다.)

So, the referencing table had two foreign key columns, and also it had a constraint to guarantee that exactly one table (not both, not neither) was referenced by a single row.

Here's how it could look when applied to your tables:

CREATE TABLE dbo.[Group]
(
    ID int NOT NULL CONSTRAINT PK_Group PRIMARY KEY,
    Name varchar(50) NOT NULL
);

CREATE TABLE dbo.[User]
(
    ID int NOT NULL CONSTRAINT PK_User PRIMARY KEY,
    Name varchar(50) NOT NULL
);

CREATE TABLE dbo.Ticket
(
    ID int NOT NULL CONSTRAINT PK_Ticket PRIMARY KEY,
    OwnerGroup int NULL
      CONSTRAINT FK_Ticket_Group FOREIGN KEY REFERENCES dbo.[Group] (ID),
    OwnerUser int NULL
      CONSTRAINT FK_Ticket_User  FOREIGN KEY REFERENCES dbo.[User]  (ID),
    Subject varchar(50) NULL,
    CONSTRAINT CK_Ticket_GroupUser CHECK (
      CASE WHEN OwnerGroup IS NULL THEN 0 ELSE 1 END +
      CASE WHEN OwnerUser  IS NULL THEN 0 ELSE 1 END = 1
    )
);

As you can see, the Ticket table has two columns, OwnerGroup and OwnerUser, both of which are nullable foreign keys. (The respective columns in the other two tables are made primary keys accordingly.) The CK_Ticket_GroupUser check constraint ensures that only one of the two foreign key columns contains a reference (the other being NULL, that's why both have to be nullable).

(The primary key on Ticket.ID is not necessary for this particular implementation, but it definitely wouldn't harm to have one in a table like this.)


Yet another option is to have, in Ticket, one column specifying the owning entity type (User or Group), second column with referenced User or Group id and NOT to use Foreign Keys but instead rely on a Trigger to enforce referential integrity.

Two advantages I see here over Nathan's excellent model (above):

  • More immediate clarity and simplicity.
  • Simpler queries to write.

CREATE TABLE dbo.OwnerType
(
    ID int NOT NULL,
    Name varchar(50) NULL
)

insert into OwnerType (Name) values ('User');
insert into OwnerType (Name) values ('Group');

I think that would be the most general way to represent what you want instead of using a flag.

참고URL : https://stackoverflow.com/questions/7844460/foreign-key-to-multiple-tables

반응형