具有2个父表的SQL外键问题

具有2个父表的SQL外键问题,sql,database,database-design,Sql,Database,Database Design,我有两个表User和Group。 我有一个表属性,由用户和组共享,其中包含列: attributeName AttributeValue ObjectID ObjectID指向用户的主键或组的主键。 我在删除时添加了一个带有级联的外部约束,以便在删除用户或组时自动删除属性 现在的问题是,当我为用户插入属性时,我有一个外键约束,因为该组不存在 如何继续?我认为您应该允许此外键字段ObjectId使用NULL值,这样您就可以插入不引用任何用户或组的ObjectId=NULL的任何行 为了更好的设

我有两个表
User
Group
。 我有一个表
属性
,由用户和组共享,其中包含列:

  • attributeName
  • AttributeValue
  • ObjectID
ObjectID
指向用户的主键或组的主键。 我在删除时添加了一个带有
级联的外部约束
,以便在删除用户或组时自动删除属性

现在的问题是,当我为用户插入属性时,我有一个外键约束,因为该组不存在


如何继续?

我认为您应该允许此外键字段
ObjectId
使用
NULL
值,这样您就可以插入不引用任何用户或组的
ObjectId
=NULL的任何行


为了更好的设计,您应该删除此
ObjectId
列,在两个表
User
Group
中添加一个新列
AttributeId
,我认为您应该允许此外键字段
ObjectId

的值为
NULL
,这样,您就可以插入
ObjectId
=null且不引用任何用户或组的任何行


为了更好地设计,您应该删除此
ObjectId
列,向两个表
User
Group
添加一个新列
AttributeId
,因为您发现不能将一列作为两个不同表的外键。如果用户不存在具有相同id的组,则不能为其添加属性。当然,您也不知道该属性是针对用户还是针对组

从评论中,您还提到了用户和组之间的m:m关系,因此我建议如下

create table [User]
(
  UserID int identity primary key,
  Name varchar(50) not null
)

go

create table [Group]
(
  GroupID int identity primary key,
  Name varchar(50) not null
)

go

create table UserGroup
(
  UserID int not null references [User](UserID),
  GroupID int not null references [Group](GroupID),
  primary key (UserID, GroupID)
)

go

create table UserAttribute
(
  UserAttributeID int identity primary key,
  Name varchar(50) not null,
  Value varchar(50) not null,
  UserID int not null references [User](UserID) on delete cascade
)

go

create table GroupAttribute
(
  GroupAttributeID int identity primary key,
  Name varchar(50) not null,
  Value varchar(50) not null,
  GroupID int not null references [Group](GroupID) on delete cascade
)

注意:属性表的使用应该针对您之前不知道的属性。您知道的所有属性都应该是实际表中的字段。保留对客户定义的属性的使用

正如您所发现的,不能将一列作为两个不同表的外键。如果用户不存在具有相同id的组,则不能为其添加属性。当然,您也不知道该属性是针对用户还是针对组

从评论中,您还提到了用户和组之间的m:m关系,因此我建议如下

create table [User]
(
  UserID int identity primary key,
  Name varchar(50) not null
)

go

create table [Group]
(
  GroupID int identity primary key,
  Name varchar(50) not null
)

go

create table UserGroup
(
  UserID int not null references [User](UserID),
  GroupID int not null references [Group](GroupID),
  primary key (UserID, GroupID)
)

go

create table UserAttribute
(
  UserAttributeID int identity primary key,
  Name varchar(50) not null,
  Value varchar(50) not null,
  UserID int not null references [User](UserID) on delete cascade
)

go

create table GroupAttribute
(
  GroupAttributeID int identity primary key,
  Name varchar(50) not null,
  Value varchar(50) not null,
  GroupID int not null references [Group](GroupID) on delete cascade
)

注意:属性表的使用应该针对您之前不知道的属性。您知道的所有属性都应该是实际表中的字段。保留对客户定义的属性的使用

您基本上有3种选择:

  • 保留您当前的设计,但将
    属性.ObjectID
    替换为
    用户ID
    组ID
    ,将单独的FK分别附加到它们(一个指向
    ,另一个指向
    用户
    ),并允许其中一个为空。您还需要一个检查约束,以确保它们不是都为NULL

  • Attribute
    表拆分为
    UserAttribute
    GroupAttribute
    ,从而将每个外键拆分为自己的表

  • 使用继承,如下所示:


  • 解决方案(1)在很大程度上取决于DBMS如何处理空值上的唯一性,(1)和(2)允许相同的
    AttributeName
    用于两个不同的属性,一个用于用户,另一个用于组。

    您基本上有3个选项:

  • 保留您当前的设计,但将
    属性.ObjectID
    替换为
    用户ID
    组ID
    ,将单独的FK分别附加到它们(一个指向
    ,另一个指向
    用户
    ),并允许其中一个为空。您还需要一个检查约束,以确保它们不是都为NULL

  • Attribute
    表拆分为
    UserAttribute
    GroupAttribute
    ,从而将每个外键拆分为自己的表

  • 使用继承,如下所示:


  • 解决方案(1)高度依赖于DBMS如何处理空值上的唯一性,并且(1)和(2)允许相同的<代码>属性名< /代码>用于两个不同的属性,一个用于用户,另一个用于组。一个用于用户,一个用于组。或者用父表上的触发器替换外键和约束以捕获删除?我不会。FK的主要用途不是级联删除。它用于确保您不会为不存在的用户/组添加属性。在UserId和GroupId的属性中使用相同的字段是个坏主意。属性中可以有两列,而不是两个表,但正如我所说的,我会选择两个表。困扰我的是我复制了相同的表格。事实上,我有4个父对象:用户/组/联系人/角色。我必须创建4个相同的表来存储属性。我还有一个“链接”表,用于链接源对象(用户或组)和目标对象(用户或组)。这张桌子的设计相当简单。它是通用的IDROW | SourceID | TargetID。删除用户或组(源或目标)时,我希望自动删除此链接。对于上面的示例,此“链接”表由用户/组/联系人“共享”。。。如果我跟着你,我就必须创建十几个相同的表。我想你应该考虑两个属性表。一个用于用户,一个用于组。或者用父表上的触发器替换外键和约束以捕获删除?我不会。FK的主要用途不是级联删除。它用于确保您不会为用户/Gr添加属性