简体   繁体   中英

How to use a Foreign key in a table a primary key in another table

I have 3 tables. Courses,CourseDestails, CourseBooking.

Courses

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

CourseDetails

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)
);

courseId from courses table is used as foreign key in the CourseDetails table.

Now I want to use CourseStartDate Location & courseId from CourseDetails table in another table called CourseBooking . I know how to add CourseStartDate Location as foreign keys. But I'm confused how to add courseId from courseDetails table as foreign key in the new CourseBookings Table.

I have tried the following

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)
 );

But there is an error saying

Can't create table 'b8040777_db1.CourseBookings'

Supports transactions, row-level locking, and foreign keys

There are several issues with the declaration of table CourseBookings .


ISSUE 1

This :

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

Should be written as :

FOREIGN KEY (courseId) REFERENCES CourseDetails(courseId),

ISSUE 2

One of the columns of CourseDetails , that is referenced by a foreign key of table CourseBookings , has no index.

From the documentation :

MySQL requires indexes on foreign keys and referenced keys so that foreign key checks can be fast and not require a table scan. In the referencing table, there must be an index where the foreign key columns are listed as the first columns in the same order. Such an index is created on the referencing table automatically if it does not exist.

In table CourseDetails :

  • courseId had an index automatically created because it references Courses(courseId)
  • CourseStartDate has no index but it is the first column in the index automatically generated by the primary key constraint declaration
  • Location has no index and it is only the second column in the primary key index --> it is not possible to create a foreign key referencing it, an error is raised when you try

SOLUTION 1

It is always possible to add the missing index to the table, by adding this to the CREATE TABLE CourseDetails statement :

INDEX idx_Location (Location)

SOLUTION 2

In your use case, I suspect that what you actually need is a multicolumn foreign key (supported in InnoDB only), that references the primary key of CourseDetails (an index already exists on these columns). This will allow you to associate each record of CourseBookings with a unique parent record in CourseDetails .

Suggestion of 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)
 );

SOLUTION 3

If solution 2 fits for your use case, then it means that your schema can be optimized by creating an autoincremented integer primary key on table CourseDetails . The existing primary key can be turned into a UNIQUE constraint. Then, in table CourseBookings , you can just store a foreign key to that column.

This would give you a simple and efficient way to relate one table to the other, while avoiding duplicating information across tables (this actually leaves you with just 3 columns in CourseBookins ).

In relational database design it is usually a good practice to create such a primary key on most tables. You could consider adding one to other tables too.

Example :

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, just in case :

FOREIGN KEY (GuestNo) REFERENCES Guest(GuestNo)

Does table Guest exists in your schema (you did not show the CREATE TABLE for it) ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM