MySQL Foreign Keys Tutorial and Examples
In this article, we introduced what foreign keys are, the rules for foreign keys, and how to use them in MySQL.
In relational databases, foreign keys are used to define a constrained relationship between two entities. Foreign keys are useful for ensuring data integrity.
What is foreign keys?
Foreign keys are used to refer to other tables relative to the primary key. The foreign key associates the rows of the child table with the rows of the parent table through one or more columns of the child table corresponding to the primary key or unique key value of the parent table.
Let’s take a look at the tables country
and city
from Sakila sample database. Here is their relationship diagram:
Here is some data from the country
table:
SELECT *
FROM country
WHERE country_id = 23;
+------------+---------+---------------------+
| country_id | country | last_update |
+------------+---------+---------------------+
| 23 | China | 2006-02-15 04:44:00 |
+------------+---------+---------------------+
1 row in set (0.05 sec)
Here is some data from the city
table:
SELECT *
FROM city
WHERE country_id = 23;
+---------+---------------+------------+---------------------+
| city_id | city | country_id | last_update |
+---------+---------------+------------+---------------------+
| 46 | Baicheng | 23 | 2006-02-15 04:45:25 |
| 47 | Baiyin | 23 | 2006-02-15 04:45:25 |
| 80 | Binzhou | 23 | 2006-02-15 04:45:25 |
| 109 | Changzhou | 23 | 2006-02-15 04:45:25 |
| 136 | Datong | 23 | 2006-02-15 04:45:25 |
...
53 rows in set (0.00 sec)
From this we can see that the country
table and the city
table is a one-to-many relationship. A country can have multiple cities, and a city can only be located in one country.
If a country already has a city, then you cannot easily delete the country from the country
table, otherwise it will cause the city data to be incomplete. You also can’t set a non-existent for a city country_id
, otherwise the city data will be wrong.
Foreign key constraints ensure that the data is complete and correct.
Foreign Key Syntax
Let’s look at the foreign key constraints defined by the city
table:
SHOW CREATE TABLE city\G
*************************** 1\. row ***************************
Table: city
Create Table: CREATE TABLE `city` (
`city_id` smallint unsigned NOT NULL AUTO_INCREMENT,
`city` varchar(50) NOT NULL,
`country_id` smallint unsigned NOT NULL,
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`city_id`),
KEY `idx_fk_country_id` (`country_id`),
CONSTRAINT `fk_city_country` FOREIGN KEY (`country_id`)
REFERENCES `country` (`country_id`)
ON DELETE RESTRICT
ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=601 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
Note some of it:
CONSTRAINT `fk_city_country` FOREIGN KEY (`country_id`)
REFERENCES `country` (`country_id`)
ON DELETE RESTRICT
ON UPDATE CASCADE
A foreign key is defined here:
-
After the
CONSTRAINT
keywordfk_city_country
is the name of the foreign key. It is optional. -
Following the
FOREIGN KEY
keyword is the column name that is the foreign key. -
Following the
REFERENCES
keyword are the referenced tables and columns. -
ON DELETE
andON UPDATE
specify the constraint strategy to be taken when deleting or updating data in the referenced table. You can use one of the following 3 strategies:CASCADE
: If a row in the referenced table is deleted or updated, the value of the matching row in child table is automatically deleted or updated.SET NULL
: If a row in the referenced table is deleted or updated, the value of the matching row in child table is set toNULL
.RESTRICT
: A MySQL error is raised when attempting to delete or update a row in the referenced table if a row in the referenced table has a matching row in child table. This is the default policy.
Usually, the table to which the foreign key belongs is called the child table, and the table referenced by the foreign key is called the parent table.
Add Foreign Key Syntax
If the foreign key is not defined when the table is created, you can also add the foreign key later by using the following syntax:
ALTER TABLE child_table_name
ADD [CONSTRAINT foreign_key_name]
FOREIGN KEY (column))
REFERENCES parent_table_name (column);
Here:
- Use the
ALTER TABLE
statement to modify the definition of the table. - Use to
ADD [CONSTRAINT foreign_key_name]
clause add a constraint namedforeign_key_name
.[CONSTRAINT foreign_key_name]
is optional. - A foreign key is defined using
FOREIGN KEY (column)) REFERENCES parent_table_name (column)
.
Delete Foreign Key Syntax
To drop a foreign key on a table, one of the following two syntaxes can be used:
-
ALTER TABLE table_name DROP FOREIGN KEY foreign_key_name;
-
ALTER TABLE table_name DROP CONSTRAINT constraint_name;
Here:
- Use the
ALTER TABLE
statement to modify the definition of the table. - Specify the foreign key name after
DROP FOREIGN KEY
, that is, the constraint name. - Specify the constraint name after
DROP CONSTRAINT
. It can remove any constraint by name, not just foreign keys.
FOREIGN KEY Examples
The following example will create user
and user_hobby
two tables in the testdb
database. Where foreign keys are used in the user_hobby
table to reference the user
table. Let’s create the user
table first, and the user_hobby
table will be created according to the respective situation in the following examples. Please follow the steps below:
-
Log in to the MySQL database as the
root
user:mysql -u root -p
Enter the password of the
root
user.Note: You can also log in as any other user with appropriate database privileges.
-
Select the
testdb
database using the following statement:USE testdb;
If you haven’t created the database yet, run the following statement first:
CREATE DATABASE testdb;
-
Create a table named
user
:CREATE TABLE `user` ( `user_id` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(45) NOT NULL, PRIMARY KEY (`user_id`));
-
Insert two rows in to the user table:
INSERT INTO user (user_id, name) VALUES (1, "Tim"), (2, "Lucy");
So far, we have created the user
table.
CASCADE strategy
If ON DELETE
and ON UPDATE
use the CASCADE
strategy:
- When a row in the parent table is deleted, the matching row in the child table is also deleted.
- When the key value of the row in the parent table is updated, the fields of the matching row in the child table are also updated.
Use the following SQL to create the user_hobby
table with a foreign key using the CASCADE
strategy.
DROP TABLE IF EXISTS user_hobby;
CREATE TABLE `user_hobby` (
`hobby_id` INT NOT NULL AUTO_INCREMENT,
`user_id` INT NOT NULL,
`hobby` VARCHAR(45) NOT NULL,
PRIMARY KEY (`hobby_id`),
CONSTRAINT `fk_user`
FOREIGN KEY (`user_id`)
REFERENCES `user` (`user_id`)
ON DELETE CASCADE
ON UPDATE CASCADE);
Insert rows into two tables:
DELETE FROM user;
DELETE FROM user_hobby;
INSERT INTO user (user_id, name)
VALUES (1, "Tim");
INSERT INTO user_hobby (hobby_id, user_id, hobby)
VALUES (1, 1, 'Football'), (2, 1, 'Swimming');
At this point the rows in the user_hobby
table as following:
+----------+---------+----------+
| hobby_id | user_id | hobby |
+----------+---------+----------+
| 1 | 1 | Football |
| 2 | 1 | Swimming |
+----------+---------+----------+
Let’s take a look at the associated operation of the child table caused by the UPDATE
and DELETE
operation on the parent table:
-
UPDATE
operate on the parent tableWe modify the value of the key
user_id
in the parent tableuser
from1
to100
:UPDATE user SET user_id = 100 WHERE user_id = 1;
At this point the rows in the
user_hobby
table:+----------+---------+----------+ | hobby_id | user_id | hobby | +----------+---------+----------+ | 1 | 100 | Football | | 2 | 100 | Swimming | +----------+---------+----------+ 2 rows in set (0.00 sec)
We found that the column values โโof those rows in the table
user_hobby
that matchuser_id = 1
inuser
table are also modified to100
. -
DELETE
operate on the parent tableDELETE FROM user WHERE user_id = 100;
At this point the data in the
user_hobby
table:Empty set (0.00 sec)
We found that those rows in the
user_hobby
table that matcheduser_id = 100
inuser
table were deleted.
RESTRICT strategy
If the ON DELETE
and ON UPDATE
use the RESTRICT
strategy:
- MySQL prohibits deletion of rows in parent tables that match child tables.
- MySQL prohibits deleting the value of the key of the row in the parent table that matches the child table.
Use the following SQL to create the user_hobby
table with foreign keys using the RESTRICT
strategy.
DROP TABLE IF EXISTS user_hobby;
CREATE TABLE `user_hobby` (
`hobby_id` INT NOT NULL AUTO_INCREMENT,
`user_id` INT NOT NULL,
`hobby` VARCHAR(45) NOT NULL,
PRIMARY KEY (`hobby_id`),
CONSTRAINT `fk_user`
FOREIGN KEY (`user_id`)
REFERENCES `user` (`user_id`)
ON DELETE RESTRICT
ON UPDATE RESTRICT);
Insert data into two tables:
DELETE FROM user;
DELETE FROM user_hobby;
INSERT INTO user (user_id, name)
VALUES (1, "Tim");
INSERT INTO user_hobby (hobby_id, user_id, hobby)
VALUES (1, 1, 'Football'), (2, 1, 'Swimming');
At this point the rows in the user_hobby
table:
+----------+---------+----------+
| hobby_id | user_id | hobby |
+----------+---------+----------+
| 1 | 1 | Football |
| 2 | 1 | Swimming |
+----------+---------+----------+
Let’s see the result of the UPDATE
and DELETE
operation on the parent table:
-
UPDATE
operate on the parent tableUPDATE user SET user_id = 100 WHERE user_id = 1;
The MySQL server returned the following error:
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`testdb`.`user_hobby`, CONSTRAINT `fk_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`) ON DELETE RESTRICT ON UPDATE RESTRICT)
-
DELETE
operate on the parent tableDELETE FROM user WHERE user_id = 1;
The MySQL server returned the following error:
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`testdb`.`user_hobby`, CONSTRAINT `fk_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`) ON DELETE RESTRICT ON UPDATE RESTRICT)
SET NULL policy
If the ON DELETE
and ON UPDATE
use the SET NULL
strategy:
- When a row of the parent table is deleted, the value of the column of the matching row in the child table is set to
NULL
. - When the key value of a row in the parent table is updated, the column value of the matching row in the child table is set to
NULL
.
Use the following SQL to create the user_hobby
table with foreign keys using the SET NULL
strategy.
DROP TABLE IF EXISTS user_hobby;
CREATE TABLE `user_hobby` (
`hobby_id` INT NOT NULL AUTO_INCREMENT,
`user_id` INT,
`hobby` VARCHAR(45) NOT NULL,
PRIMARY KEY (`hobby_id`),
CONSTRAINT `fk_user`
FOREIGN KEY (`user_id`)
REFERENCES `user` (`user_id`)
ON DELETE SET NULL
ON UPDATE SET NULL);
Insert data into two tables:
DELETE FROM user;
DELETE FROM user_hobby;
INSERT INTO user (user_id, name)
VALUES (1, "Tim");
INSERT INTO user_hobby (hobby_id, user_id, hobby)
VALUES (1, 1, 'Football'), (2, 1, 'Swimming');
Let’s take a look at the associated operation of the child table caused by the UPDATE
and DELETE
operation on the parent table:
-
UPDATE
operate on the parent tableUPDATE user SET user_id = 100 WHERE user_id = 1;
At this point the data in the
user_hobby
table:+----------+---------+----------+ | hobby_id | user_id | hobby | +----------+---------+----------+ | 1 | NULL | Football | | 2 | NULL | Swimming | +----------+---------+----------+ 2 rows in set (0.00 sec)
After updated the parent table rows, these rows related in the child table are set to
NULL
. -
DELETE
operate on the parent tableSince the above example modifies the data of the table, we reinitialize the data of the two tables:
DELETE FROM user; DELETE FROM user_hobby; INSERT INTO user (user_id, name) VALUES (1, "Tim"); INSERT INTO user_hobby (hobby_id, user_id, hobby) VALUES (1, 1, 'Football'), (2, 1, 'Swimming');
DELETE FROM user WHERE user_id = 100;
At this point the data in the
user_hobby
table:+----------+---------+----------+ | hobby_id | user_id | hobby | +----------+---------+----------+ | 1 | NULL | Football | | 2 | NULL | Swimming | +----------+---------+----------+ 2 rows in set (0.00 sec)
After deleted the parent table rows, these rows related in the child table are set to
NULL
.
Self-referencing foreign keys
Sometimes, the child table and the parent table may be the same table. A foreign key in such a table is called a self-referential foreign key.
Typically, self-referential foreign keys are defined in tables that represent tree-like data structures. For example, a table representing categories:
CREATE TABLE category (
category_id INT AUTO_INCREMENT PRIMARY KEY,
category_name VARCHAR(45),
parent_category_id INT,
CONSTRAINT fk_category FOREIGN KEY (parent_category_id)
REFERENCES category (category_id)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
In this table, the parent_category_id
column is a foreign key. It references the category_id
column of the category
table.
This table implements an infinite hierarchy of classification trees. A category can have multiple subcategories, and a subcategory can have 0 or 1 parent category;
Enable or Disable Foreign Key Constraints
To disable foreign key constraints, use the following statement:
SET foreign_key_checks = 0;
To enable foreign key constraints, use the following statement:
SET foreign_key_checks = 1;
Disabling foreign key constraints is useful when bulk importing data.
Conclusion
In this article, we introduced what foreign keys are, the rules for foreign keys, and how to use them in MySQL. Here are the main points of this article:
- Foreign keys are used to define constraints between two entities. Foreign keys are useful for ensuring data integrity.
- The table that defines the foreign key is called the child table, and the table referenced by the foreign key is called the parent table.
- The foreign key refers to the primary key or unique key column of the parent table.
- The
ALTER TABLE ... ADD FOREIGN KEY ...
statement can be used to add foreign keys. - The
ALTER TABLE ... DROP FOREIGN KEY ...
statement can be used to delete foreign keys. - A self-referential foreign key refers to the table itself. This is used to implements tree-like data structures.