简体   繁体   English

外键列映射到多个主键

[英]Foreign Key column mapped to multiple primary keys

I have a database which has three tables我有一个包含三个表的数据库

Messages - PK = MessageId消息 - PK = MessageId
Drafts - PK = DraftId草稿 - PK = DraftId
History - FK = RelatedItemId历史记录 - FK = RelatedItemId

The History table has a single foreign Key [RelatedItemId] which maps to one of the two Primary keys in Messages and Drafts . History 表有一个外键[RelatedItemId] ,它映射到MessagesDrafts中的两个主键之一。

Is there a name for this relationship?这种关系有名字吗?

Is it just bad design?这只是糟糕的设计吗?

Is there a better way to design this relationship?有没有更好的方法来设计这种关系?

Here are the CREATE TABLE statements for this question:以下是此问题的 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 )
)

In a short description the solution you have used is called:在简短的描述中,您使用的解决方案称为:
Polymorphic Association多态关联
Objective : Reference Multiple Parents目标:参考多个父母
Resulting anti-pattern: Use dual-purpose foreign key, violating first normal form (atomic issue), loosing referential integrity产生的反模式:使用双用途外键,违反第一范式(原子问题),失去参照完整性
Solution: Simplify the Relationship解决方案:简化关系

More information about the problem .有关该问题的更多信息

BTW createing a common super-table will help you:顺便说一句,创建一个通用的超级表将帮助您:

在此处输入图片说明

Is there a name for this relationship?这种关系有名字吗?

There is no standard name that I'm aware of, but I've heard people using the term "generic FKs" or even " inner-platform effect" .没有我知道的标准名称,但我听说有人使用术语“通用 FK”甚至“内部平台效应”

Is it just bad design?这只是糟糕的设计吗?

Yes.是的。

The reason: it prevents you from declaring a FOREIGN KEY, and therefore prevents the DBMS from enforcing referential integrity directly.原因:它阻止您声明 FOREIGN KEY,因此阻止 DBMS 直接强制执行参照完整性。 Therefore you must enforce it trough imperative code, which is surprisingly difficult .因此,您必须通过命令式代码强制执行它,这非常困难

Is there a better way to design this relationship?有没有更好的方法来设计这种关系?

Yes.是的。

Create separate FOREIGN KEY for each referenced table.为每个引用的表创建单独的 FOREIGN KEY。 Make them NULL-able, but make sure exactly one of them is non-NULL, through a CHECK constraint.通过 CHECK 约束使它们能够为 NULL,但确保其中一个是非 NULL。

Alternatively, take a look at inheritance .或者,看看继承

Best practice I have found is to create a Function that returns whether the passed in value exists in either of your Messages and Drafts PK columns.我发现的最佳实践是创建一个函数,该函数返回传入的值是否存在于 Messages 和 Drafts PK 列中。 You can then add a constraint on the column on the History that calls this function and will only insert if it passes (ie it exists).然后,您可以在调用此函数的 History 上的列上添加一个约束,并且只有在它通过(即它存在)时才会插入。

Adding non-parsed example Code:添加未解析的示例代码:

CREATE FUNCTION is_related_there ( IN @value uniqueidentifier ) RETURNS TINYINT BEGIN IF (select count(DraftId) from Drafts where DraftId = @value + select count(MessageId) from Messages where MessageId = @value) > 0 THEN RETURN 1; CREATE FUNCTION is_related_there ( IN @value uniqueidentifier ) RETURNS TINYINT BEGIN IF (select count(DraftId) from Drafts where DraftId = @value + select count(MessageId) from Messages where MessageId = @value) > 0 THEN RETURN 1; ELSE RETURN 0;否则返回 0; END IF;万一; END;结尾;

ALTER TABLE History ADD CONSTRAINT CK_HistoryExists CHECK (is_related_there (RelatedItemId) = 1) ALTER TABLE History ADD CONSTRAINT CK_HistoryExists CHECK (is_related_there (RelatedItemId) = 1)

Hope that runs and helps lol希望运行并帮助哈哈

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM