データベースに関連するテーブルが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フィールドを介して、グループまたはユーザーが所有できます。
MOST CORRECTチケットとオプションのユーザーまたはグループの間のこの関係を説明する方法は何でしょうか?
チケットテーブルに、所有しているタイプを示すフラグを追加する必要があると考えています。
いくつかのオプションがあり、すべて「正確さ」と使いやすさが異なります。いつものように、適切な設計はニーズに依存します。
チケットにOwnedByUserIdとOwnedByGroupIdの2つの列を作成し、各テーブルにNULL入力可能な外部キーを設定するだけです。
Ticket:userとticket:groupの両方の関係を有効にするM:M参照テーブルを作成できます。おそらく将来的には、単一のチケットを複数のユーザーまたはグループが所有できるようにしたいと思うでしょうか?この設計では、チケットを1つのエンティティのみが所有する必要があります。
すべてのユーザーに対してデフォルトグループを作成し、真のグループまたはユーザーのデフォルトグループのいずれかによってチケットを単純に所有させることができます。
または(私の選択)ユーザーとグループの両方のベースとして機能するエンティティをモデル化し、そのエンティティがチケットを所有します。
投稿したスキーマを使用した大まかな例を次に示します。
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 のリストの最初のオプションは、私がかつて作業したプロジェクトで実装されたもので、3つのテーブル間で同様の関係が確立されていました。 (そのうちの1つは、他の2つを一度に1つずつ参照しました。)
そのため、参照元のテーブルには2つの外部キー列があり、1つの行で1つのテーブル(両方ではなく、どちらでもない)が参照されることを保証する制約もありました。
テーブルに適用した場合の外観は次のとおりです。
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
)
);
ご覧のとおり、Ticket
テーブルにはOwnerGroup
とOwnerUser
の2つの列があり、どちらもNULL入力可能な外部キーです。 (他の2つのテーブルのそれぞれの列は、それに応じて主キーになります。)CK_Ticket_GroupUser
チェック制約は、2つの外部キー列の一方のみが参照を含むことを保証します(もう一方はNULL )。
(Ticket.ID
の主キーは、この特定の実装には必要ありませんが、このようなテーブルにキーを入れても害はありません。)
さらに別のオプションは、Ticket
に所有エンティティタイプ(User
またはGroup
)を指定する1つの列、参照されるUser
またはGroup
を持つ2番目の列を持つことです。 idおよびNOTは外部キーを使用しますが、代わりにトリガーを使用して参照整合性を強制します。
Nathanの excellent model (上記)よりも優れている2つの利点: