代码之家  ›  专栏  ›  技术社区  ›  Dzinx

如何使用非唯一外键强制DB完整性?

  •  5
  • Dzinx  · 技术社区  · 15 年前

    (name, version) . 因此,示例表如下所示:

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

    因此,如果用户想要更新person的数据,他们不会进行更新,而是创建一个具有相同 name version 价值向用户显示的数据(对于给定的 名称 )是最高的那个吗 版本 .

    我还有第二张表,比如说狗,它在persons表中引用了persons:

    TABLE DOGS:
        id:         int,
        name:       varchar(30),
        owner_name: varchar(30),
        ...
    

    明显地 owner_name 是指 PERSONS.name 人名 不是独一无二的!

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

    我正在寻找最优雅的解决方案——我知道我可以在PERSONS表上使用触发器,但这并不像我希望的那样声明性和优雅。有什么想法吗?


    补充资料

    上面的设计有以下优点,如果我需要,我可以“记住”一个人的电流 id (或 我确信该行中的数据永远不会更改。这一点很重要,例如,如果我将此人的数据作为文档的一部分,然后进行打印,并且在5年内有人可能希望打印一份完全不变的副本(例如,使用与今天相同的数据),那么这对他们来说将非常容易。

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


    编辑:

    8 回复  |  直到 15 年前
        1
  •  5
  •   A-K    15 年前

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

        2
  •  2
  •   Michael Gattuso    15 年前

    或者,您可以为具有历史价值的数据维护个人历史记录表。通过这种方式,您可以保持您的人员和狗表整洁,参考资料简单,但也可以访问历史上有趣的信息。

        3
  •  1
  •   Jon Seigel    15 年前

    好的,首先你需要规范化你的表。谷歌“数据库规范化”,你会得到大量的阅读资料。人员表尤其需要注意。

    第二件事是,当您创建外键引用时,99.999%的时间您希望引用ID(数字)值。也就是说,[DOGS].[owner]应该是对[PERSONS].[id]的引用。

    编辑:添加示例模式(请原谅松散的语法)。我假设每只狗只有一个主人。这是 实现个人历史的方法。所有列都不是空的。

    Persons Table:
    int Id
    varchar(30) name
    ...
    
    PersonHistory Table:
    int Id
    int PersonId (foreign key to Persons.Id)
    int Version (auto-increment)
    varchar(30) name
    ...
    
    Dogs Table:
    int Id
    int OwnerId (foreign key to Persons.Id)
    varchar(30) name
    ...
    

    最新版本的数据将直接存储在Persons表中,较旧的数据存储在PersonHistory表中。

        4
  •  0
  •   Preet Sangha    15 年前

    我将使用和关联表将多个版本链接到一个pk。

        5
  •  0
  •   andyb    15 年前

    我参与的一个项目解决了一个类似的问题。这是一个生物记录数据库,随着新的研究提高了对分类学的理解,物种名称可以随着时间的推移而改变。

        6
  •  0
  •   shahkalpesh    15 年前

    珀森斯


    名称
    .....
    activeVersion(这将是personVersionInfo中的UID)

    PersonVersionInfo

    UID(标识人员+版本的唯一标识符),
    id(int),


    versionId(将为每个人生成)

    多吉德,
    狗名
    ......

    带狗的人


    教条

    编辑:你必须加入PersonWithDogs,PersonVersionInfo,Dogs才能获得完整的图片(从今天开始)。这种结构将帮助你把狗和主人联系起来(有一个特定的版本)。


    在这种结构中,一个人可以养很多狗。

    您的场景(可以更改的内容/限制等)将有助于更好地设计模式。

        7
  •  0
  •   Dzinx    15 年前

    解决方案1

    在PERSONS表中,我们只保留名称(唯一标识符)和指向的链接 现在的 个人资料:

    TABLE PERSONS:
        name:            varchar(30),
        current_data_id: int
    

    我们创建一个新表PERSONS_DATA,其中包含该人员的所有数据历史记录:

    TABLE PERSONS_DATA:
        id:      int
        version: int (auto-generated)
        ... // some data, like address, etc.
    

    优点:对于每只狗,至少有一个PERSONS\u数据行包含其所有者的数据(这就是我想要的)

    缺点:如果你想更改某人的数据,你必须:

    1. 添加新的PERSONS_数据行
        8
  •  0
  •   Dzinx    15 年前

    解决方案2

    TABLE PERSONS:
        name:            varchar(30),
        first_data_id: int
    

    我们创建一个新表PERSONS_DATA,其中包含该人员的所有数据历史记录:

    TABLE PERSONS_DATA:
        id:      int
        name:    varchar(30)
        version: int (auto-generated)
        ... // some data, like address, etc.
    

    优势:

    • 对于每只狗,至少有一个PERSONS\u数据行包含其所有者的数据(这就是我想要的)
    • 如果我想更改一个人的数据,我不必更新PERSONS行,只需添加一个新的PERSONS\u数据行

    缺点:要检索当前人员的数据,我必须:

    • 选择具有给定名称和最高版本的PERSONS_数据(可能很昂贵)
    • 选择具有特殊版本的PERSONS_数据,例如“-1”,但每次添加新PERSONS_数据时,我都必须更新两行PERSONS_数据,在这个解决方案中,我希望避免必须更新两行。。。