如何在一个表中使用外键,在另一个表中使用主键

时间:2019-01-30 01:46:43

标签: mysql sql database database-design

我有3张桌子。课程,课程详细信息,课程预订。

课程

CREATE TABLE Courses (
    courseId int NOT NULL,
    courseName varchar(255),
    level varchar(255),
    description varchar(255),  
    PRIMARY KEY (courseId)
);

课程详细信息

CREATE TABLE CourseDetails (
    CourseStartDate int NOT NULL,
    Location varchar(255) NOT NULL,
    MaxNoPlaces int,
    Length int,
    Instructor varchar(255),
    TotalPlacesBooked int,
    NoPlacesCancelled int,
    AdultPrice int,
    ChildPrice int, 
    courseId int,
    CONSTRAINT PK_CourseDetails PRIMARY KEY (CourseStartDate,Location,courseId),
    FOREIGN KEY (courseId) REFERENCES Courses(courseId)
);
来自Course表的

courseId用作CourseDetails表中的外键。

现在,我想在另一个名为CourseStartDate的表中使用CourseDetails表中的CourseBooking Location&courseId。我知道如何将CourseStartDate位置添加为外键。但是我很困惑如何从CourseDetails表中将courseId添加为新CourseBookings表中的外键。

我尝试了以下

CREATE TABLE CourseBookings (
    CourseStartDate int NOT NULL,
    Location varchar(255) NOT NULL,
    GuestNo int, 
    courseId int,
    CONSTRAINT PK_CourseDetails PRIMARY KEY (CourseStartDate,Location,GuestNo,courseId),
    FOREIGN KEY (courseId) REFERENCES CourseDetails.courseId(courseId),
    FOREIGN KEY (CourseStartDate) REFERENCES CourseDetails(CourseStartDate),
    FOREIGN KEY (Location) REFERENCES CourseDetails(Location),
    FOREIGN KEY (GuestNo) REFERENCES Guest(GuestNo)
 );

但是有一个错误提示

  

无法创建表'b8040777_db1.CourseBookings'

支持事务,行级锁定和外键

1 个答案:

答案 0 :(得分:2)

CourseBookings的声明存在几个问题。


问题1

此:

FOREIGN KEY (courseId) REFERENCES CourseDetails.courseId(courseId),

应写为:

FOREIGN KEY (courseId) REFERENCES CourseDetails(courseId),

问题2

CourseDetails的外键引用的CourseBookings列之一没有索引。

来自the documentation

  

MySQL要求在外键和引用键上建立索引,以便外键检查可以快速进行,而无需进行表扫描。在引用表中,必须有一个索引,其中外键列以相同的顺序列为第一列。如果该索引不存在,则会在引用表上自动创建。

在表CourseDetails中:

  • courseId具有自动创建的索引,因为它引用了Courses(courseId)
  • CourseStartDate没有索引,但是它是由主键约束声明自动生成的索引中的第一列
  • Location没有索引,它只是主键索引中的第二列->无法创建引用它的外键,尝试时会出现错误

解决方案1 ​​

始终可以通过将缺失的索引添加到表CREATE TABLE CourseDetails中来将缺失的索引添加到表中:

INDEX idx_Location (Location)

解决方案2

在您的用例中,我怀疑您实际需要的是一个多列外键(仅在InnoDB中受支持),该外键引用CourseDetails的主键(这些列上已经存在一个索引)。这样,您就可以将CourseBookings的每个记录与CourseDetails中的唯一父记录相关联。

DDL建议:

CREATE TABLE CourseBookings (
    CourseStartDate int NOT NULL,
    Location varchar(255) NOT NULL,
    GuestNo int, 
    courseId int,
    CONSTRAINT PK_CourseDetails PRIMARY KEY (CourseStartDate,Location,courseId,GuestNo),
    FOREIGN KEY (CourseStartDate,Location,courseId) 
        REFERENCES CourseDetails(CourseStartDate,Location,courseId),
    FOREIGN KEY (GuestNo) REFERENCES Guest(GuestNo)
 );

解决方案3

如果解决方案2适合您的用例,则意味着可以通过在表CourseDetails上创建一个自动递增的整数主键来优化您的模式。可以将现有的主键转换为UNIQUE约束。然后,在表CourseBookings中,您可以仅将外键存储到该列。

这将为您提供一种简单有效的方法,将一个表与另一个表相关联,同时避免在表之间重复信息(实际上,您在CourseBookins中仅留下3列)。

在关系数据库设计中,通常最好在大多数表上创建这样的主键。您也可以考虑将一个表添加到其他表中。

示例:

CREATE TABLE CourseDetails (
    id int PRIMARY KEY AUTO_INCREMENT,
    CourseStartDate int NOT NULL,
    ...
    CONSTRAINT PK_CourseDetails UNIQUE (CourseStartDate,Location,courseId),
    FOREIGN KEY (courseId) REFERENCES Courses(courseId)
);

CREATE TABLE CourseBookings (
    id int PRIMARY KEY AUTO_INCREMENT,
    courseDetailId INT NOT NULL,
    GuestNo int, 
    CONSTRAINT PK_CourseBookings UNIQUE (courseDetailId,GuestNo),
    FOREIGN KEY (courseDetailId) REFERENCES CourseDetails(id),
    FOREIGN KEY (GuestNo) REFERENCES Guest(GuestNo)
);

PS,以防万一:

FOREIGN KEY (GuestNo) REFERENCES Guest(GuestNo)

Guest是否存在于您的模式中(您没有显示CREATE TABLE)?