我有两个表通过一对多的关系相互连接。 问题是引用的表还有第二个表的外键!
我知道这很令人困惑,所以我会告诉你一个简单的数据库设计:
作者
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)
为每个作者指定默认书。
现在,两个表都相互依赖,所以我不能删除任何项目,除非我删除它们之间的关系,它感觉不对!
关于此设计是否存在缺陷的任何想法以及我该怎么办?
答案 0 :(得分:2)
我会用第三个表连接另外两个表来实现它。你最终会得到:
<强>作者强>
AuthorId Name
-------- -------
1 John
2 Mike
3 Mig
<强> DefaultBook 强>
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
设置UNIQUE约束,可以防止每个作者拥有多个默认值。如果您需要删除作者,只需删除其默认值以及与他相关的任何书籍,即可删除作者。
这有一个问题是很难强制每个作者都有一本默认书,但这个要求是导致你首先遇到这个问题的原因。
答案 1 :(得分:1)
您可以从作者中删除DefaultBookId
,向图书添加IsDefaultForAuthor
列,然后应用约束,以便每位作者只有一本标记为IsDefaultForAuthor
的图书。
当然,这并不能解决由多位作者撰写的书籍等问题,但我假设这是您正在展示的玩具示例,而不是您的实际系统建模。
答案 2 :(得分:1)
原则上这个设计没问题,但当然你已经在实践中发现了一个问题。
以下是您可以尝试的一些事项:
如果您的数据库支持它(oracle确实),则会延迟您的约束。这只会检查提交的约束,因此您可以在一个事务中删除一本书及其作者。 (con:非常特定于数据库)
而不是authors.defaultBookId使用books.isAuthorsDefaultBook。 (con:很难为每个作者强制执行一个默认书;应该可以使用基于功能的索引索引和/或物化视图,这可能是db dependend)
删除defaultBookId上的not null约束并信任你的应用程序正确执行(con:失去数据库的某些功能)
澄清:
删除defaultBookId上的not null约束允许将其设置为null,删除以前引用的书,然后删除作者。对于创作相同的作品,但顺序相反。