error 1215: CANNOT ADD FOREIGN KEY CONSTRAINT ; Composite Foreign key - mysql

I am getting ERROR CODE 1215: cannot add foreign key constraint for the child table.
Parent table has composite primary key. I want to use that composite primary key as foreign key in the child table.
Please guide me.
PARENT TABLE
CREATE TABLE health.procedures(
Specialty varchar(40),
Procedure_Name varchar(60),
PRIMARY KEY (Procedure_Name, Specialty)
);
CHILD TABLE
CREATE TABLE health.procedureProvided(
specialization varchar(40),
procedure_name varchar(60),
Insurance_ID int REFERENCES health.insurance (idInsurance),
Hospital_ID int REFERENCES health.hospital (idHospital) ,
Doctor_ID int REFERENCES health.doctor( idDoctor) ,
CONSTRAINT procedures_fk foreign key (specialization,procedure_name)references health.procedures(Specialty,Procedure_Name) ,
PRIMARY KEY (specialization, procedure_name, Insurance_ID, Hospital_ID, Doctor_ID)
);

You are specifying a foreign key that is invalid. Your primary key is procedure_name in health.procedure, but you are trying to create a composite foreign key in health.procedureProvided. You can't create that as a foreign key as the column Specialty in the master table is not part of the primary. A foreign key must contain all the columns in the contributing table's primary key but cannot contain values that are not in that primary key. You have three real options. 1. Specify Specialty as being a component of the primary key in procedure. Unfortunately that means the procedure will not necessarily by unique, it will be unique by specialty. 2. add a surrogate key - a system generated sequence value, uuid or something else (timestamps are not recommended). 3. Create validation tables valid_procedures and valid_specialties and use the table health.procedure as an intersection between those to provide valid procedures and correlated specialties and then you could migrate the entire primary key.

Related

Error Code: 1824. Failed to open the referenced table even though it is already created

I am building a database for a school project, but for some reason I cannon make a foreign key reference between 2 tables (only those 2). My project has 14 tables and it works fine for all the others.
The tables are made like:
create table degree(
title varchar(50),
idryma varchar(40),
bathmida enum('High School', 'Univercity', 'Master', 'PHD'),
constraint degree_id primary key (title, idryma)
);
create table has_degree(
degree_title varchar(50),
degree_idryma varchar(40),
employee_username varchar(12),
acquisition_year year(4),
grade float(3,1),
constraint has_degree_id primary key (degree_title, degree_idryma, employee_username)
);
And then I try to alter the table so that I make the foreign key connections:
alter table has_degree add foreign key (degree_title) references degree(title);
alter table has_degree add foreign key (degree_idryma) references degree(idryma);
But I keep on getting
Error Code: 1824. Failed to open the referenced table 'degree'
I have tried to make them like that:
create table degree(
title varchar(50),
idryma varchar(40),
bathmida enum('High School', 'Univercity', 'Master', 'PHD'),
constraint degree_id primary key (title, idryma)
);
create table has_degree(
degree_title varchar(50),
degree_idryma varchar(40),
employee_username varchar(12),
acquisition_year year(4),
grade float(3,1),
foreign key (degree_title) references degree(title),
foreign key (degree_idryma) references degree(idryma),
/*employee is an other table that I use and that works just fine*/
foreign key (employee_username) references employee(employee_username),
constraint has_degree_id primary key (degree_title, degree_idryma, employee_username)
);
But the only thing that changes is that I get
Error Code: 1822. Failed to add the foreign key constraint. Missing index for constraint 'has_degree_ibfk_2' in the referenced table 'degree'
The columns in your foreign key in table has_degree must be the same as the columns in the primary key of the referenced table degree.
In this case, the primary key of degree consists of two varchar columns.
So the foreign key in has_degree that references it must also be only two varchar columns, and values in those columns in has_degree must match exactly the values in a row of degree.
You defined the foreign key this way:
foreign key (degree_title) references degree(title),
foreign key (degree_idryma) references degree(idryma),
But that's two foreign keys, each having a single column. You need one foreign key with two columns:
foreign key (degree_title, degree_idryma) references degree(title, idryma),

Using Composite Primary Key As Foreign Key

I've always thought that if I were going to use a foreign key that referenced a composite primary key, I'd need to include all the columns of the composite primary key in both tables.
I was confused when I inadvertently didn't do this and received no errors. In the example below, RoomId ISN'T unique, and yet it's allowed to be used as a foreign key by itself.
CREATE TABLE Buildings (
BuildingName VARCHAR(4) PRIMARY KEY,
CampusId TINYINT,
StreetAddress VARCHAR(50),
City VARCHAR(30),
State CHAR(2),
Zip CHAR(5)
);
CREATE TABLE Rooms (
RoomId VARCHAR(5),
BuildingName VARCHAR(20) NOT NULL,
RoomType VARCHAR(15),
Capacity INT,
Notes VARCHAR(100),
CONSTRAINT FK_Buildings_Rooms FOREIGN KEY (BuildingName) REFERENCES Buildings(BuildingName),
PRIMARY KEY (RoomId, BuildingName)
);
CREATE TABLE Instructors(
EmployeeId INT AUTO_INCREMENT PRIMARY KEY,
OfficeId VARCHAR(5),
CONSTRAINT Fk_Instructors_Rooms FOREIGN KEY (OfficeId) REFERENCES Rooms(RoomId));
If I switch the order in the composite primary key to (BuildingName, RoomId), then the foreign key declaration produces the expected error:
Error Code: 1822. Failed to add the foreign key constraint. Missing index for constraint 'Fk_Instructors_Rooms' in the referenced table 'rooms'
MySQL has extended the traditional definition of foreign keys. In most databases, they are limited to unique or primary keys. As with some other "extensions", the documentation explicitly warns against referring to a non-unique key:
However, the system does not enforce a requirement that the referenced columns be UNIQUE or be declared NOT NULL. The handling of foreign key references to nonunique keys or keys that contain NULL values is not well defined for operations such as UPDATE or DELETE CASCADE. You are advised to use foreign keys that reference only UNIQUE (including PRIMARY) and NOT NULL keys.
Of course, not including all the components of a composite key means that you are using a non-unique key.
Your issue with composite primary keys is an interesting one. Personally, I would chalk it up as yet another reason to use auto-incremented primary keys. Single columns are less prone to error in foreign key declarations.
Foreign keys do not need to reference unique or primary key fields. They can reference the first field(s) of any index (primary, unique, or plain).

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

How do I make a column not null and be a foreign key in MySQL

I am trying to create a table that is a foreign key of another table and make it not null, but I am running into trouble making both happen. I was able to successfully get foreign keys working that did not require NOT NULL but I can't get both working.
Here is the line giving me trouble
CONSTRAINT instructor FOREIGN KEY (id) REFERENCES Instructor(id) NOT NULL
then I get the error:
CONSTRAINT instructor FOREIGN KEY (id) REFERENCES Instructor(id) NOT NULL,
*
ERROR at line 5:
ORA-00907: missing right parenthesis
Also, I am getting a weird error when trying to create a table (note, this table is created after creating the table that contains the above error) where it fails at a very trivial part:
CREATE TABLE Enrollment (
CONSTRAINT class_id FOREIGN KEY (id) REFERENCES Class(id) NOT NULL,
CONSTRAINT member_id FOREIGN KEY (id) REFERENCES RecCenterMember(id) NOT NULL,
cost int NOT NULL
);
Then for that command I get this error:
CREATE TABLE Enrollment (
*
ERROR at line 1:
ORA-00904: : invalid identifier
How can I fix these two errors?
You need to create the column before you try creating constraints on the column.
You have:
CREATE TABLE Enrollment (
CONSTRAINT class_id FOREIGN KEY (id) REFERENCES Class(id) NOT NULL,
CONSTRAINT member_id FOREIGN KEY (id) REFERENCES RecCenterMember(id) NOT NULL,
cost int NOT NULL
);
You need:
CREATE TABLE Enrollment (
id INT NOT NULL CONSTRAINT class_id REFERENCES Class(id),
CONSTRAINT member_id FOREIGN KEY (id) REFERENCES RecCenterMember(id),
cost INT NOT NULL
);
Note that in the first line, the FOREIGN KEY isn't necessary because the column is implied. In the second line, the id is identified. You could also write:
CREATE TABLE Enrollment
(
id INT NOT NULL,
CONSTRAINT class_id FOREIGN KEY (id) REFERENCES Class(id),
CONSTRAINT member_id FOREIGN KEY (id) REFERENCES RecCenterMember(id),
cost INT NOT NULL
);
It is unusual, though not automatically wrong, to make a single column (id) be a foreign key of two tables simultaneously. It isn't clear if you actually want three columns in your table — and if you do, which column names are in your table.
You could also use the appropriate notation for an automatically allocated type in MySQL syntax (SERIAL instead of INT NOT NULL, or add AUTO_INCREMENT, etc).
Maybe you're really after:
CREATE TABLE Enrollment
(
id SERIAL,
class_id INT NOT NULL CONSTRAINT class_id REFERENCES Class(id),
member_id INT NOT NULL CONSTRAINT member_id REFERENCES RecCenterMember(id),
cost INT NOT NULL
);
This makes more sense in general. You're creating a new enrollment record for a pre-existing class, and for a pre-existing recreation centre member, and recording its cost.
Syntax diagrams vs actual behaviour
If, as Michael - sqlbot suggests — and I've no reason whatsoever to disbelieve him — MySQL recognizes but does not respond to the REFERENCES clause in a column definition in a CREATE TABLE statement but only acts on full FOREIGN KEY clauses, then you have to adjust my suggested answers from their syntactically correct but semantically ignored form to something like:
Option 1 (minimally changing the SQL from the question):
CREATE TABLE Enrollment (
id INT NOT NULL,
CONSTRAINT class_id FOREIGN KEY (id) REFERENCES Class(id),
CONSTRAINT member_id FOREIGN KEY (id) REFERENCES RecCenterMember(id),
cost int NOT NULL
);
Option 2 (what I consider the most plausible version):
CREATE TABLE Enrollment
(
id SERIAL,
class_id INT NOT NULL,
CONSTRAINT fk_class_id FOREIGN KEY (class_id) REFERENCES Class(id),
member_id INT NOT NULL,
CONSTRAINT fk_member_id FOREIGN KEY (member_id) REFERENCES RecCenterMember(id),
cost INT NOT NULL
);
Or some other variant of this syntax based on the desired table schema ignoring the FK constraints, then adding the constraints along the lines shown.
Key Point
You must define the columns before you define the foreign keys based on those columns.

MySQL Error Code 1215: Cannot add foreign key Constraint

I'm very new to SQL, I'm trying to define a 2 tables Hospital and Hospital_Address but when I'm trying to add foreign key in Hospital_Address it throws an error: "1215: Cannot add foreign key"
create table Hospital (
HId Int not null,
HName varchar(40) not null,
HDept int, Hbed Int,
HAreaCd int not null,
Primary Key (HId)
);
create table Hospital_Address (
HAreaCd Int not null,
HArea varchar(40) not null,
HCity varchar(40),
HAdd1 varchar(40),
HAdd2 varchar(40),
Primary Key (HArea),
foreign key (HAreaCd) references Hospital (HAreaCd));
Please help me in this regard. Thanks in advance.
MySQL requires that there be an index on the HAreaCd column in the parent Hospital table, in order for you to reference that column in a FOREIGN KEY constraint.
The normative pattern is for the FOREIGN KEY to reference the PRIMARY KEY of the parent table, although MySQL extends that to allow a FOREIGN KEY to reference a column that is a UNIQUE KEY, and InnoDB extends that (beyond the SQL standard) and allows a FOREIGN KEY to reference any set of columns, as long as there is an index with those columns as the leading columns (in the same order specified in the foreign key constraint.) (That is, in InnoDB, the referenced columns do not need to be unique, though the behavior with this type of relationship may not be what you intend.)
If you create an index on that column in Hospital table, e.g.:
CREATE INDEX Hospital_IX1 ON Hospital (HAreaCd);
Then you can create a foreign key constraint that references that column.
However, because this is a non-standard extension of MySQL and InnoDB, the "best practice" (as other answers here indicate) is for a FOREIGN KEY to reference the PRIMARY KEY of the foreign table. And ideally, this will be a single column.
Given the existing definition of the Hospital table, a better option for a foreign key referencing it would be to add the Hid column to the Hospital_Address table
... ADD HId Int COMMENT 'FK ref Hospital.HId'
... ADD CONSTRAINT FK_Hospital_Address_Hospital
FOREIGN KEY (HId) REFERENCES Hospital (HId)
To establish the relationship between the rows, the values of the new HId column will need to be populated.
You cannot add a foreign key to a non-primary key element of another table usually.
If you really need to do so, refer to this question for help : Foreign Key to non-primary key
HAreaCd in the Hospital table should be a primary key. Only then can you reference it in the Hospital_Address table