设计表时如何实现一对一,一对多和多对多关系?


281

谁能解释在设计带有示例的表时如何实现一对一,一对多和多对多关系?


实施往往会根据目标RDBMS的不同而有所不同,因此您要针对的供应商是什么?
billinkc 2011年

1
这不是一个作业问题...!我正在准备接受采访。.所以想在这里问...我尝试使用谷歌搜索,但找不到任何好的文章可以一一解释所有这些内容...!
阿森纳

我的目标是oracle数据库.. !!
阿森纳

您可能需要阅读这篇文章,以及.... stevencalise.wordpress.com/2010/09/01/... 我将密切注意点2和3
tsells

3
@tsells有时会问您一些问题,这些问题不适用于您简历中的内容或直接适用于工作要求的问题。我得到了要在一家公司面试我的人的清单,其中一个是数据库专家。我的履历表上没有SQL,但是我进行了一些简单的SQL查询。它帮助了我,找到了工作。后来我发现,招聘经理担心求职者在压力下的反应。他们是否承认自己的限制或伪造自己的通过方式?如果他们承认自己的极限,他们还是尝试还是放弃得太早?
Doug Cuthbertson

Answers:


478

一对一:使用外键访问被引用的表:

student: student_id, first_name, last_name, address_id
address: address_id, address, city, zipcode, student_id # you can have a
                                                        # "link back" if you need

您还必须在外键列上设置唯一约束(addess.student_id)以防止子表(address)中的多行与引用表(student)中的同一行相关。

一对多:在关系的许多方面使用外键链接回“一侧”:

teachers: teacher_id, first_name, last_name # the "one" side
classes:  class_id, class_name, teacher_id  # the "many" side

多对多:使用联结表(示例):

student: student_id, first_name, last_name
classes: class_id, name, teacher_id
student_classes: class_id, student_id     # the junction table

查询示例:

 -- Getting all students for a class:

    SELECT s.student_id, last_name
      FROM student_classes sc 
INNER JOIN students s ON s.student_id = sc.student_id
     WHERE sc.class_id = X

 -- Getting all classes for a student: 

    SELECT c.class_id, name
      FROM student_classes sc 
INNER JOIN classes c ON c.class_id = sc.class_id
     WHERE sc.student_id = Y


1
在一对一关系中“反向链接”何时有用的一个很好的例子是什么?感谢您简洁明了的回答。
dev_feed 2014年

1
@dev_feed就数据库设计而言,我认为返回链接没有好处,但是使用上面的示例可以大大简化查找student给定的的过程address
edhedges 2014年

@NullUserException我们是否需要3个表用于多对多关系。不能由两个表进行多对多关系。

1
@Cody每student_classes行应该只有一对一的关系。如果studentAin classA和中classB,则in中应该有两行student_classes,其中一行与之相关。
NullUserException

11
在一对一关系中,联接字段在两个表中都应该是唯一的。它可能在一个表上可以保证唯一性,但它可能需要在另一个表上具有唯一索引的PK。
HLGEM '16

70

以下是关系类型的一些实际示例:

一对一(1:1)

当且仅当表A中的一条记录与表B中的最多一条记录相关时,这种关系才是一对一的关系。

若要建立一对一关系,表B的主键(无孤立记录)必须是表A的辅助键(有孤立记录)。

例如:

CREATE TABLE Gov(
    GID number(6) PRIMARY KEY, 
    Name varchar2(25), 
    Address varchar2(30), 
    TermBegin date,
    TermEnd date
); 

CREATE TABLE State(
    SID number(3) PRIMARY KEY,
    StateName varchar2(15),
    Population number(10),
    SGID Number(4) REFERENCES Gov(GID), 
    CONSTRAINT GOV_SDID UNIQUE (SGID)
);

INSERT INTO gov(GID, Name, Address, TermBegin) 
values(110, 'Bob', '123 Any St', '1-Jan-2009');

INSERT INTO STATE values(111, 'Virginia', 2000000, 110);

一对多(1:M)

当且仅当表A中的一条记录与表B中的一个或多个记录相关时,这种关系才是一对多的。但是,表B中的一条记录不能与表A中的多条记录相关。

若要建立一对多关系,表A(“一个”表)的主键必须是表B(“许多”表)的辅助键。

例如:

CREATE TABLE Vendor(
    VendorNumber number(4) PRIMARY KEY,
    Name varchar2(20),
    Address varchar2(20),
    City varchar2(15),
    Street varchar2(2),
    ZipCode varchar2(10),
    Contact varchar2(16),
    PhoneNumber varchar2(12),
    Status varchar2(8),
    StampDate date
);

CREATE TABLE Inventory(
    Item varchar2(6) PRIMARY KEY,
    Description varchar2(30),
    CurrentQuantity number(4) NOT NULL,
    VendorNumber number(2) REFERENCES Vendor(VendorNumber),
    ReorderQuantity number(3) NOT NULL
);

多对多(M:M)

当且仅当表A中的一条记录与表B中的一条或多条记录相关时,这种关系才是多对多的,反之亦然。

要建立多对多关系,请创建第三个表“ ClassStudentRelation”,该表将具有表A和表B的主键。

CREATE TABLE Class(
    ClassID varchar2(10) PRIMARY KEY, 
    Title varchar2(30),
    Instructor varchar2(30), 
    Day varchar2(15), 
    Time varchar2(10)
);

CREATE TABLE Student(
    StudentID varchar2(15) PRIMARY KEY, 
    Name varchar2(35),
    Major varchar2(35), 
    ClassYear varchar2(10), 
    Status varchar2(10)
);  

CREATE TABLE ClassStudentRelation(
    StudentID varchar2(15) NOT NULL,
    ClassID varchar2(14) NOT NULL,
    FOREIGN KEY (StudentID) REFERENCES Student(StudentID), 
    FOREIGN KEY (ClassID) REFERENCES Class(ClassID),
    UNIQUE (StudentID, ClassID)
);

第一个示例:GID号(6)和SGID号(4),为什么?SGID也应该不是(6)吗?在第二个示例number(4)和number(2)...
obeliksz

@obeliksz可以为空吗?

为什么在M:N的末尾使用UNIQUE(StudentID,ClassID)?
strix25

1
@ strix25为了避免在多次创建相同的ClassStudentRelation行时重复进行操作,因为如果您不确定外键StudentID和ClassID都是唯一的,那么什么会停止创建具有相同StudentID和ClassID的新行呢?因为它们在上面的代码中不是唯一的。因此,您可以像上面的代码一样实现它,或者添加一个包含StudentID和ClassID的主键,以避免重复在ClassStudentRelation中创建同一行。
Fouad Boukredine

1
@valik数据库中的数据通过引用现有数据而不是多次创建相同的数据来工作,为什么要这样做?当然您不必这样做,否则效率不高。考虑到这一点,让我们回到您的示例(詹姆斯有生物学而生物学有詹姆斯),当然可以,但是无需创建数据库中已经存在的另一条数据。您需要做的就是在您要创建任何关系时仅引用已经存在的关系。希望对您
有所

8

这是一个非常常见的问题,所以我决定将这个答案变成一篇文章

一对多

一对多表关系如下所示:

一对多

在关系数据库系统中,一对多表关系基于Foreign Key子级中的一列链接两个表,该列引用了Primary Key父表行的。

在上面的表格图post_id中,post_comment表格中的列Foreign Keypost表格ID Primary Key列具有关联:

ALTER TABLE
    post_comment
ADD CONSTRAINT
    fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post

一对一

一对一的表关系如下所示:

一对一

在关系数据库系统中,一对一表关系基于Primary Key子级中的一列链接两个表,该列也是对子表的Foreign Key引用Primary Key父级表行。

因此,我们可以说子表共享 Primary Key与父表。

在上面的表图id中,post_details表中的列也Foreign Keypostid Primary Key列有关系:

ALTER TABLE
    post_details
ADD CONSTRAINT
    fk_post_details_id
FOREIGN KEY (id) REFERENCES post

多对多

多对多表关系如下所示:

多对多

在关系数据库系统中,多对多表关系通过子表链接两个父表,该子表包含Foreign Key引用Primary Key两个父表的列的两列。

在上面的表图post_id中,post_tag表中的列也Foreign Keypost表id Primary Key列有关系:

ALTER TABLE
    post_tag
ADD CONSTRAINT
    fk_post_tag_post_id
FOREIGN KEY (post_id) REFERENCES post

而且,tag_id在列post_tag表中有一个Foreign Key与关系tag表ID Primary Key列:

ALTER TABLE
    post_tag
ADD CONSTRAINT
    fk_post_tag_tag_id
FOREIGN KEY (tag_id) REFERENCES tag

3

一对一(1-1)关系: 这是主键和外键之间的关系(与外键相关的主键仅一个记录)。这是一对一的关系。

一对多(1-M)关系: 这也是主键和外键关系之间的关系,但是这里的主键涉及多个记录(即表A具有书籍信息,表B具有多个书籍出版者)。

多对多(MM):多对多包括两个维度,下面将通过示例进行详细说明。

-- This table will hold our phone calls.
CREATE TABLE dbo.PhoneCalls
(
   ID INT IDENTITY(1, 1) NOT NULL,
   CallTime DATETIME NOT NULL DEFAULT GETDATE(),
   CallerPhoneNumber CHAR(10) NOT NULL
)
-- This table will hold our "tickets" (or cases).
CREATE TABLE dbo.Tickets
(
   ID INT IDENTITY(1, 1) NOT NULL,
   CreatedTime DATETIME NOT NULL DEFAULT GETDATE(),
   Subject VARCHAR(250) NOT NULL,
   Notes VARCHAR(8000) NOT NULL,
   Completed BIT NOT NULL DEFAULT 0
)
-- This table will link a phone call with a ticket.
CREATE TABLE dbo.PhoneCalls_Tickets
(
   PhoneCallID INT NOT NULL,
   TicketID INT NOT NULL
)

8
如果您还添加了主键和外键约束,那会更好更好。
Ashish K Gupta
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.