让我们看一个例子 - 书籍。一本书可以有1个作者。作者可以拥有1..m的书籍。代表书籍所有作者的好方法是什么?
我提出了创建Books表和Authors表的想法。 Authors表具有作者姓名的主AuthorID密钥。 Books表具有主要书籍ID和有关书籍的元数据(标题,出版日期等)。但是,需要有一种方法将书籍与作者和作者联系起来。这就是问题所在。
让我们说鲍勃有三本书。然而,在一本书中,他将其写成Bob博士。另一位他写作鲍勃博士,第三位是罗伯特博士。我希望能够确定这样一个事实,即这些作者实际上是同一个人,但却以不同的名字存在。我也希望将鲍勃与另一位写不同书籍的鲍勃区分开来。
现在让我们在应用程序中添加另一个部分,一个跟踪有趣人物的Person表。让我们说Bob是一个有趣的人。我想不仅要说这三本书的作者都是鲍勃,而且这个有趣的鲍勃与作者鲍勃是鲍勃一样。
那么对于这种可能复杂的映射存在什么策略,同时确保书籍作者通过封面上的名称来识别?
答案 0 :(得分:29)
添加另一个名为BookAuthors的表,其中包含BookID,AuthorID和NameUsed的列。 NameUsed的NULL值意味着将其从Author的表中拉出来。这称为交叉表。
答案 1 :(得分:7)
你需要三张桌子 -
图书将包含图书ID,图书标题以及您需要收集的有关图书的所有其他信息。
作者将包含作者ID以及其他信息,例如您需要收集的关于任何特定作者的名字,姓氏。
BookAuthors是一个多对多连接,包含BookID,AuthorID和NameUsed。这将允许该书具有零或多个作者,对于作者具有零或多本书,以及关于要捕获的该关系的信息。例如,你也可以在BookAuthor表上有一个专栏,用于描述作者与该书的关系(“编辑者”,“前言词”)。
答案 2 :(得分:6)
我认为你几乎就在那里。您需要一个Books表,一个Authors表,然后是一个“authors_of_books”表,其中包含该书的主键,作者的主键以及一个“引用为”的文本字段,显示该特定作者在该书中的引用方式
答案 3 :(得分:3)
这听起来像是多对多的关系,而不是1对多的关系。我想你会想要在这两者之间使用一个表,它允许你在其中任何一方定义1对多。看看这个......
http://www.tekstenuitleg.net/en/articles/database_design_tutorial/8
答案 4 :(得分:1)
鉴于Bob博士和Robert博士以及博士博士都是同一个人,他们会链接到作者表中的同一行。
但是,我认为你需要的是作者链接的人员表。您还可以将有趣的人员表链接到它。这样作者鲍勃和作者罗伯特以及有趣的鲍勃链接到人鲍勃。希望这是有道理的。
答案 5 :(得分:1)
首先想到的是有一个链接表,也许叫做AuthorOf来将书籍与作者联系起来。
列可以是AuthorID,BookID,也可能是CreditAs,因此您可以区分Bob博士和Bob博士。 (以及斯蒂芬金和理查德巴赫曼等笔名)。
您仍然可以唯一地识别作者。
答案 6 :(得分:1)
看起来你真的想要创建一系列自定义连接表,用于将项目从一个实体关联到另一个实体。
我会从最细微的层面开始,并且说任何作者必须是一个人。我会简化这个过程。
创建一个包含人员信息和PersonId的人员表,将信息放在那里。
然后创建一个BookAuthors表,其中有3列BookId,PersonId,TitledName。这样你可以根据需要使用不同的名称,如果没有,你可以使用COALESE或类似的东西获得默认名称,如果TitledName为null。
只是一个想法..
答案 7 :(得分:1)
你所问的真的不是你如何处理1..n关系,而是n..n关系(对作者有效,有很多书,一本书可以有很多作者)。
处理此问题的经典方法是通过中间表,所以
作者表(authorID,authorDetails) 书桌(bookID,书籍详情) AuthorBook表(authorID,bookID)
如果您真的为改变作者姓名而烦恼,那么请使用1..n作者详细信息表,添加
AuthorDetails(authorID,itemID,authorDetails)
并从作者表中删除authorDetails
答案 8 :(得分:0)
对于1..n关系(作者有很多书,作者有很多别名):
如果您愿意,可以使用中间表来链接作者和书籍,但是使用1..n映射我不认为这是必要的。
对于n..m关系(作者有很多书,书有很多作者):
您必须使用中间联接表(author_id,alias_id,book_id)而不是book表中的外键。您需要将别名中的外键保留为作者(以便轻松查找作者别名而无需通过所有书籍)。
你可以争辩说,就未来的可扩展性而言,这也是一种更好的开始,即使初始规范说某事是1..n关系。您会发现给出的规格(或问题)通常是不充分的,因此您需要以一般方式设计规格何时更改或澄清。
答案 9 :(得分:0)
postgresql中的一个可能的实现,只是为了它的乐趣:
create table books (
book_id integer primary key,
title varchar not null
);
create table aliases (
alias_id integer primary key,
alias varchar not null
);
create table books_aliases (
book_id integer references books (book_id),
alias_id integer references aliases (alias_id),
primary key (book_id, alias_id)
);
create table authors (
author_id integer primary key,
author varchar not null,
interesting boolean default false
);
create table aliases_authors (
alias_id integer references aliases (alias_id),
author_id integer references authors (author_id),
primary key (alias_id, author_id)
);
create view books_aliases_authors as
select * from books
natural join books_aliases
natural join aliases
natural join aliases_authors
natural join authors;
可以使用“使用”代替自然联接:
create view books_aliases_authors as
select *
from books
join books_aliases using (book_id)
join aliases using (alias_id)
join aliases_authors using (alias_id)
join authors using (author_id);
或为mysql兼容性做复杂的事情(注意mysql也需要上面varchars的显式最大长度):
create view books_aliases_authors as
select b.book_id, title, l.alias_id, alias, t.author_id, author, interesting
from books b
join books_aliases bl on bl.book_id = b.book_id
join aliases l on bl.alias_id = l.alias_id
join aliases_authors lt on lt.alias_id = l.alias_id
join authors t on t.author_id = lt.author_id;
这个例子不使用“people”表,只是作者的“有趣”标志。请注意,如果您将“作者”重命名为“人物”, nothing 会发生变化(结构上)