外键到多个表

我在我的数据库中有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字段拥有。

最正确的方法是什么才能描述票证和可选用户或组之间的这种关系?

我想我应该在票据表中添加一个标志,说明什么types拥有它。

你有几个select,都在“正确性”和易用性上有所不同。 一如既往,正确的devise取决于您的需求。

  • 您可以简单地在Ticket,OwnedByUserId和OwnedByGroupId中创build两列,并为每个表都设置可为空的Fks。

  • 您可以创build启用票证:用户和票证:组关系的M:M参考表。 也许将来你会希望允许一张票被多个用户或组所拥有? 这种devise并不强制一张票只能由一个实体拥有。

  • 您可以为每个用户创build一个默认组,并拥有由真实组或用户的默认组拥有的票据。

  • 或者(我的select)模拟一个实体,作为用户和组的基础,并且拥有该实体的所有者。

下面是使用您的发布架构的一个粗略示例:

 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 NOT NULL, 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 NOT NULL, 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 NOT NULL, [Owner] int NOT NULL references dbo.Party(PartyId), [Subject] varchar(50) NULL ) 

@Nathan Skerl列表中的第一个选项是在我曾经工作过的一个项目中实现的,三个表之间build立了类似的关系。 (其中一个引用了另外两个,一次一个。)

所以,引用表有两个外键列,并且还有一个约束来保证只有一个表(不是两者都不是)被一行引用。

以下是应用于表格时的外观:

 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表有两列, OwnerGroupOwnerUser ,它们都是可空的外键。 (另外两个表中的相应列被相应地作为主键。) CK_Ticket_GroupUser检查约束确保两个外键列中只有一个包含引用(另一个是NULL,这就是为什么两者都必须为空)。

Ticket.ID的主键对于这个特定的实现是不必要的,但是在这样的表中有一个表是绝对不会有害的。)

 CREATE TABLE dbo.OwnerType ( ID int NOT NULL, Name varchar(50) NULL ) insert into OwnerType (Name) values ('User'); insert into OwnerType (Name) values ('Group'); 

我认为这将是最普遍的方式来代表你想要的,而不是使用一个标志。