如何使用非唯一外键强制执行数据库完整性?

Dzi*_*inX 5 sql sql-server foreign-keys unique

我希望有一个数据库表,用于保存包含修订历史记录的数据(如维基百科上的页面).我认为一个好主意是有两列标识行:(name, version).所以样本表看起来像这样:

TABLE PERSONS:
    id:      int,
    name:    varchar(30),
    version: int,
    ... // some data assigned to that person.
Run Code Online (Sandbox Code Playgroud)

因此,如果用户想要更新人员的数据,他们不会进行更新 - 相反,他们会创建具有相同name但不同version值的新PERSONS行.向用户显示的数据(给定的name)是最高的数据version.

我有第二张表,比如说DOGS,它引用了PERSONS表中的人物:

TABLE DOGS:
    id:         int,
    name:       varchar(30),
    owner_name: varchar(30),
    ...
Run Code Online (Sandbox Code Playgroud)

显然,owner_name是一个引用PERSONS.name,但我不能将它声明为外键(在MS SQL Server中),因为PERSONS.name它不是唯一的!

问题:那么,在MS SQL Server 2008中,我应该如何确保数据库完整性(即,对于每个DOG,PERSONS中至少存在一行,使得其PERSON.name == DOG.owner_name)?

我正在寻找最优雅的解决方案 - 我知道我可以在PERSONS表上使用触发器,但这不像我想要的那样具有声明性和优雅性.有任何想法吗?


附加信息

上面的设计具有以下优点:如果我需要,我可以"记住"一个人的当前id(或(name, version)对),并且我确信该行中的数据永远不会被更改.这很重要,例如,如果我把这个人的数据作为随后打印的文档的一部分,并且在5年内有人可能想要打印完全未更改的副本(例如,使用与今天相同的数据),那么这将非常容易为他们做.

也许您可以想到一个完全不同的设计,它可以实现相同的目的,并且可以更容易地实现其完整性(最好使用外键或其他约束)?


编辑:感谢Michael Gattuso的回答,我发现了另一种可以描述这种关系的方式.有两种解决方案,我将其作为答案发布.请投票选择你更喜欢哪一个.

A-K*_*A-K 5

在父表中,在(id,version)上创建唯一约束.将版本列添加到子表,并使用检查约束以确保它始终为0.使用FK约束将(parentid,version)映射到父表.