SQL - "No Unique Constraint Matching Given Keys" Despite Presence of Primary Key - mysql

I'm working on a project which involves implementing a simplified version of a school database. The 3 relevant tables are listed below:
create table classes( --A given class
class_code varchar(10) primary key
);
create table class_offerings( --A particular instance of a class
class_code varchar(10),
class_name varchar(128) not null,
semester_code integer,
maximum_capacity integer check (maximum_capacity >= 0),
teacher_name varchar(50) not null, --heavily simplified
primary key (class_code, semester_code),
foreign key (class_code) references classes(class_code)
on delete cascade on update cascade
);
create table prerequisites(
prereq varchar(10),
class_code varchar(10),
semester_code integer,
primary key (class_code, semester_code),
foreign key (class_code) references classes(class_code)
on delete cascade on update cascade,
foreign key (semester_code) references class_offerings(semester_code)
on delete cascade on update cascade,
foreign key (prereq) references classes(class_code)
on delete cascade on update cascade
);
When I try and create "prerequisites," I'm given the message "ERROR: there is no unique constraint matching given keys for referenced table class_offerings." While it is true that I haven't applied the UNIQUE constraint to semester_code, it's part of the primary key, which to my understanding enforces a unique combination of all elements in the primary key. If I turn out to be wrong, I still don't want to have to apply UNIQUE to the semester_code, as multiple entries of the same semester_code should be allowed provided they don't share the same class_code. How do I fix this error?

Foreign keys can also be made up of several columns:
foreign key (class_code, semester_code)
references class_offerings(semester_code,class_code)
on delete cascade on update cascade,
Personally however, I would avoid such a design. If possible I would introduce artificial IDs as auto-increment columns that always serve a primary keys. That way foreign keys always can be on the artificial ID column.
Natural keys are good and should be put as constraints to the db as well, I would just not build relationships on natural keys. However, this is my personal preference and there are arguments for having natural keys a primary keys as well: https://sqlstudies.com/2016/08/29/natural-vs-artificial-primary-keys/

Related

Foreign Key on MySQL

I am new to SQL and I started building my own project. I am having issues creating a foreign key on my second table. . Please let me know what I am missing here.
The second CREATE TABLE statement should be:
CREATE TABLE entry (
issuer_id INT AUTO_INCREMENT PRIMARY KEY,
issuer_name VARCHAR(20) NOT NULL,
fine INT,
book_id INT,
due_date DATE,
FOREIGN KEY (book_id)
REFERENCES book_table (book_id)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (due_date)
REFERENCES book_table (due_date)
ON DELETE CASCADE
ON UPDATE CASCADE
);
A foreign key is a column or set of columns in one table that links to a unique key (typically the primary key) in another table. The columns must exist in both tables. They must match in type and the order within the key declarations. They must constitute a unique key in the foreign table.

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

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.

Duplicate entry error in 1 column of a composite key

I am trying to insert pseudo data into my db to get going, and in one particular table I have two columns which are FK's and PK's of the table; fk_product_manf_code and fk_content_id. To my understanding, these are considered composite keys in their current state.
So I add data to the table:
fk_product_manf_code fk_content_id
NOV-ABC123 1
I then want to associate another content_id to the same product_manf_code, so I perform the following:
INSERT INTO `mydb`.`package_contents`
(`fk_product_manf_code`, `fk_content_id`)
VALUES
('NOV-ABC123', 2);
However I'm greeted with the following error:
Error Code: 1062. Duplicate entry 'NOV-ABC123' for key 'fk_product_manf_code_UNIQUE'
I don't understand what's going, because I thought a composite key makes 2 columns unique? So why is it kicking up a fuss about just 1 column being unique?
Here is the table CREATE statement
CREATE TABLE `package_contents` (
`fk_product_manf_code` varchar(255) NOT NULL,
`fk_content_id` int(11) NOT NULL,
PRIMARY KEY (`fk_content_id`,`fk_product_manf_code`),
UNIQUE KEY `fk_content_id_UNIQUE` (`fk_content_id`),
UNIQUE KEY `fk_product_manf_code_UNIQUE` (`fk_product_manf_code`),
CONSTRAINT `content_id` FOREIGN KEY (`fk_content_id`) REFERENCES `contents` (`content_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `product_manf_code` FOREIGN KEY (`fk_product_manf_code`) REFERENCES `products` (`product_manf_code`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
So, you are learning why composite primary keys are a pain, especially for foreign key constraints. Not only are integer keys more efficient, but a single key is easier to work with.
I would suggest changing your table structure to be more like this:
CREATE TABLE package_contents (
package_contents_id int not null auto_increment primary key,
fk_product_manf_id int NOT NULL,
fk_content_id int(11) NOT NULL,
UNIQUE KEY (fk_content_id, fk_product_manf_id),
CONSTRAINT content_id FOREIGN KEY (fk_content_id)
REFERENCES contents(content_id) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT product_manf_code FOREIGN KEY (fk_product_manf_id)
REFERENCES products(product_manf_id) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Note that I changed the manufacturer code to an id as well. This should also reduce the size of the table, assuming that the "code" is longer than 4 bytes.
If you do this for all your tables, the database will be a bit more efficient, and you won't need superfluous unique constraints. The foreign key constraints should always be to primary keys (unless there is a very good reason for using a different unique key).

MySQL - foreign key constrained by primary key in same table, error #1452

I created a table where cat_parent_id is a foreign key is constrained by the primary key cat_id, using this:
CREATE TABLE categories (
cat_id SMALLINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
cat_parent_ID SMALLINT,
cat_name VARCHAR(40)
INDEX cat_id(cat_id),
FOREIGN KEY(cat_id) REFERENCES categories(cat_id),
);
When I try to insert a record where cat_parent_ID is NULL, I get the error:
#1452 - Cannot add or update a child row: a foreign key constraint fails (`myDatabase`.`categories`, CONSTRAINT `categories_ibfk_1` FOREIGN KEY (`cat_id`) REFERENCES `categories` (`cat_id`))
How can the foreign key constraint fail when there is no foreign key to begin with? Is the constraint only possible if null is not allowed?
I can only insert records successfully if I disable the constraint, which is not what I want. I need the parent_id to be optional, and if it has a value then it be an existing cat_id only
This will create a circular foreign key, which will prevent any insertion into the table.
FOREIGN KEY(cat_id) REFERENCES categories(cat_id),
EDIT: Perhaps you meant to put the PK on cat_parent_id?
You have one root record which doesn't have a parent. For this one, you must first disable foreign key constraints.
SET FOREIGN_KEY_CHECKS=0;
Insert the record.
Then don't forget to re-enble foreign key constraints
SET FOREIGN_KEY_CHECKS=1;
Then from now own, make sure your inserts include an existing parent.
How can the foreign key constraint fail when there is no foreign key
to begin with? Is the constraint only possible if null is not allowed?
If you want to add other records which do not have a FK value, make sure that NULL is allowed.

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