【问题标题】:A 2-way relationship (a database design flaw)双向关系(数据库设计缺陷)
【发布时间】:2011-07-11 19:45:00
【问题描述】:

我有两张表,它们通过一对多的关系相互连接。 问题是被引用的表也有第二个表的外键!

我知道这很令人困惑,所以我将向您展示我的数据库的简单设计:

作者

AuthorId      Name       DefaultBookId (FK)
--------      -------    -------------
1             John       1
2             Mike       3
3             Mig        5

书籍

BookId        Title            AuthorId (FK)
--------      -------          -------------
1             TitleInfo1       1
2             TitleInfo2       3
3             TitleInfo3       2
4             TitleInfo4       1
5             TitleInfo5       3
6             TitleInfo6       3
7             TitleInfo7       1

当然,我必须将 books 表中的 AuthorId 设为外键,这是正常情况,但现在我需要为每个作者设置默认图书,因此我将在新列上定义外键(DefaultBookId) 为每个作者指定默认书籍。

现在,两个表相互依赖,所以我不能删除任何项目,除非我删除它们之间的关系并且感觉这样做不正确!

关于这个设计是否有缺陷以及我能做些什么的任何想法?

【问题讨论】:

    标签: database database-design


    【解决方案1】:

    原则上这个设计是可以的,当然你在实践中已经发现了问题。

    您可以尝试以下方法:

    • 如果您的数据库支持它(oracle 支持),则会延迟您的约束。这只会检查提交的约束,因此您可以在一个事务中删除一本书及其作者。 (缺点:非常特定于数据库)

    • 使用 books.isAuthorsDefaultBook 代替 authors.defaultBookId。 (缺点:很难为每个作者强制执行一本默认书籍;应该可以使用基于函数的索引索引和/或物化视图,它们可能是数据库依赖的)

    • 删除 defaultBookId 上的非空约束并相信您的应用程序会正确执行(缺点:失去了数据库的某些功能)

    澄清:

    删除 defaultBookId 上的非空约束允许将其设置为空,删除以前引用的书,然后删除作者。创作相同的作品,但顺序相反。

    【讨论】:

    • 关于你的第一个选项,SqlServer 支持吗? .. 很抱歉我没有得到第三个选项,not null 约束与数据库的引用完整性有什么关系,您的意思是删除 FK 约束吗?
    • 第二个选项似乎是最好和最简单的解决方案,不会给我的设计增加任何复杂性(我、Daimen 和你已经考虑过它,这证明它很简单)但是很难更改默认书的设置,我的意思是每次我必须更改默认书籍时,我都必须连接 n 次以将 IsDefault 设置为同一作者下的其他书籍,并且当我获取作者的信息而不是仅使用 DefaultBookId 时显示默认信息,我将不得不遍历书籍并检查 IsDefault == true! .. 你怎么看 =) ?
    • 您可以使用单个更新/选择语句轻松设置和读取 isDefault 值。所以我认为这里没有太大问题。
    • 看起来 sql server 不支持可延迟约束:stackoverflow.com/questions/998095/…
    【解决方案2】:

    我将使用连接另外两个的第三个表来实现这一点。你最终会得到:

    作者

    AuthorId      Name   
    --------      -------
    1             John   
    2             Mike   
    3             Mig    
    

    默认书

    AuthorId      DefaultBookId (FK)
    --------      -------------
    1             1
    2             3
    3             5
    

    书籍

    BookId        Title            AuthorId (FK)
    --------      -------          -------------
    1             TitleInfo1       1
    2             TitleInfo2       3
    3             TitleInfo3       2
    4             TitleInfo4       1
    5             TitleInfo5       3
    

    通过在DefaultBook.AuthorId 上设置唯一约束,您可以防止每个作者拥有多个默认值。如果您需要删除作者,只需删除他的默认值以及与他关联的所有书籍,然后您就可以删除该作者。

    这样做的一个问题是很难强制每个作者都有一本默认书,但这个要求是导致您首先遇到这个问题的原因。

    【讨论】:

    • 不敢相信没有人提到过这样一个干净的解决方案.. 谢谢 =) (Y) .. 但如果你能指出你的意思是“这有一个问题是很难强制要求每个作者都有一本默认书籍,但这个要求首先导致了你遇到这个问题。”因为我认为这个解决方案没有问题! ..如果它有我看不到的缺点,请你指出来
    • @IKashef - 可能值得考虑的一件事是,无论是这个模型还是你的原始模型都不会强制默认书是由将其作为默认书的作者创作的(试着说快 5 倍)。很难判断这是否是您实际问题域中的问题。
    • @Damien +1 对于我尝试认真阅读您的评论并且忍不住笑哈哈..我真的在这里尝试!
    • 很难把它放在一起 :D .. 关于你的评论!你的意思是作者的默认书不是他写的吗? ..如果是这样,您能否再次检查我示例中的表格!当然,每条记录都匹配
    • @IKashef - 在你的例子中,每条记录都匹配 - 但我们没有做任何事情来强制,如果它是一个真正的限制(即使用你的样本数据,将作者 1 的默认书是 BookID 3 可以吗?)
    【解决方案3】:

    您可以从 Authors 中删除 DefaultBookId,将 IsDefaultForAuthor 列添加到 Books,然后应用一个约束,使每个作者只有一本标记为 IsDefaultForAuthor 的书。

    当然,这并没有解决诸如由多个作者撰写的书籍之类的问题,但我假设这是您展示的玩具示例,而不是您正在建模的实际系统。

    【讨论】:

    • 好吧,我不会面对多个作者,因为你是对的,我只是在一个简单而通用的设计上模拟了我的问题(经典书籍和作者示例).. 我已经考虑过了,但是我将如何做这部分:“应用一个约束,使每个作者只有一本书标记为 IsDefaultForAuthor”?
    • @IKashef - 依赖于数据库(和版本) - 在 SQL Server 中,您将使用过滤索引 (2008) 或索引视图 (
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-12
    • 2010-11-14
    相关资源
    最近更新 更多