外键列映射到多个主键

时间:2014-03-04 16:40:36

标签: sql database database-design

我有一个有三个表的数据库

消息 - PK = MessageId
草稿 - PK = DraftId
历史 - FK = RelatedItemId

历史记录表只有一个外键[RelatedItemId],可以映射到MessagesDrafts中的两个主键之一。

这段关系有名字吗?

这只是糟糕的设计吗?

有没有更好的方法来设计这种关系?

以下是此问题的CREATE TABLE语句:

 CREATE TABLE [dbo].[History](
    [HistoryId] [uniqueidentifier] NOT NULL,
    [RelatedItemId] [uniqueidentifier] NULL,
    CONSTRAINT [PK_History] PRIMARY KEY CLUSTERED ( [HistoryId] ASC )
 )

CREATE TABLE [dbo].[Messages](
    [MessageId] [uniqueidentifier] NOT NULL,
    CONSTRAINT [PK_Messages] PRIMARY KEY CLUSTERED (    [MessageId] ASC )
 )


CREATE TABLE [dbo].[Drafts](
    [DraftId] [uniqueidentifier] NOT NULL,
    CONSTRAINT [PK_Drafts] PRIMARY KEY CLUSTERED (  [DraftId] ASC )
)

3 个答案:

答案 0 :(得分:4)

在简短描述中,您使用的解决方案称为:
多态协会
目标:参考多个父母 产生的反模式:使用两用外键,违反第一范式(原子问题),失去参照完整性
解决方案:简化关系

More information about the problem

BTW创建一个共同的超级表将帮助你:

enter image description here

答案 1 :(得分:2)

  

这段关系有名字吗?

我没有注意到标准名称,但我听说有人使用“通用FK”这个术语甚至“inner-platform effect"

  

这只是糟糕的设计吗?

原因:它阻止您声明FOREIGN KEY,因此阻止DBMS直接强制引用完整性。因此,您必须通过命令式代码强制执行此操作,即surprisingly difficult

  

有没有更好的方法来设计这种关系?

为每个引用的表创建单独的FOREIGN KEY。使它们成为NULL,但通过CHECK约束确保它们中的一个非NULL。

或者,请查看inheritance

答案 2 :(得分:0)

我发现的最佳实践是创建一个Function,它返回传入的值是否存在于Messages和Drafts PK列中。然后,您可以在调用此函数的历史记录上的列上添加约束,并且只有在它通过时才会插入(即它存在)。

添加未解析的示例代码:

CREATE FUNCTION is_related_there(    IN @value uniqueidentifier) 返回TINYINT 开始    IF(从草稿中选择计数(DraftId),其中DraftId = @value + select Messages(MessageId)from Messages where MessageId = @value)> 0那么       返回1;    其他       返回0;    万一; END;

ALTER TABLE历史记录添加约束     CK_HistoryExists CHECK(is_related_there(RelatedItemId)= 1)

希望运行并帮助lol