Foreign Keys

You are viewing an old version of this article. View the current version here.

Overview

A foreign key is a constraint which can be used to enforce data integrity. It is composed by a column (or a set of columns) in a table called the child table, which references to a column (or a set of columns) in a table called the parent table. If foreign keys are used, MariaDB performs some checks to enforce that some integrity rules are always enforced.

Foreign keys can only be used with storage engines which support them. InnoDB and the obsolete PBXT support foreign keys.

Syntax

Foreign keys are created with CREATE TABLE or ALTER TABLE. The definition must follow this syntax:

[CONSTRAINT [symbol]] FOREIGN KEY
    [index_name] (index_col_name, ...)
    REFERENCES tbl_name (index_col_name,...)
    [ON DELETE reference_option]
    [ON UPDATE reference_option]

reference_option:
    RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT

The symbol clause, if secified, is used in error messages and must be unique in the database.

The columns in the child table must be an index, or the leftmost part of an index. Index prefixes are not supported (thus, TEXT and BLOB columns cannot be used as foreign keys). If MariaDB automatically creates an index for the foreign key (because it does not exists and is not explicitally created), its name will be index_name.

The foreign key columns and the referenced columns must be of the same type or similar types. For integer types, the size and sign must also be the same.

The parent and the child table must use the same storage engine, and must not be TEMPORARY or partitioned tables. They can be the same table.

Constraints

If a foreign keys exists, each row in the child table must match a row in the parent table. A child row matches a parent row if all its foreign key values are identical to a parent row's values in the parent table. However, if at least one of the foreign key values is NULL, the row has no parents, but it is still allowed.

MariaDB performs certain checks to guarantee that the data integrity is enforced:

  • Trying to insert non-matching rows produce an error.
  • When a row in the parent table is deleted and a child row exists, MariaDB performs an action which depends from the ON DELETE clause of the foreign key.
  • When a value in the column referenced by a foreign key changes and a child row exists, MariaDB performs an action which depends from the ON UPDATE clause of the foreign key.
  • A table cannot be dropped if it is referenced by a foreign key and the child table is not empty.

The allowed actions for ON DELETE and ON UPDATE are:

  • RESTRICT: The change on the parent table is prevented. The statement terminates with an error. This is the default behavior for both ON DELETE and ON UPDATE.
  • NO ACTION: Synonym for RESTRICT.
  • CASCADE: The change is allowed and progragates on the child table. For example, if a parent row is deleted, the child row is also deleted; if a parent row's ID change, the child row's ID will also change.
  • SET NULL: The change is allowed, and the parent row's foreign key columns are set to NULL.
  • SET DEFAULT: Only worked with PBXT. Similar to SET NULL, but the foreign key columns were set to their default values.

Metadata

The Information Schema REFERENTIAL_CONSTRAINTS table contains information about foreign keys. The individual columns are listed in the KEY_COLUMN_USAGE table.

The InnoDB-specific Information Schema tables also contain information about the InnoDB foreign keys. The foreign key information is stored in the INNODB_SYS_FOREIGN. Data about the individual columns are stored in INNODB_SYS_FOREIGN_COLS.

The most human-readable way to get information about a table's foreign keys sometimes is the SHOW CREATE TABLE statement.

Examples

Let's see an example. We will create an author table and a book table. Both tables have a primary key called id. book also has a foreign key composed by a field called author_id, which refers to the author primary key. The foreign key constraint name is optional, but we'll specify it because we want it to appear in error messages: fk_book_author.

CREATE TABLE author (
	id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
	name VARCHAR(100) NOT NULL
) ENGINE = InnoDB;

CREATE TABLE book (
	id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
	title VARCHAR(200) NOT NULL,
	author_id SMALLINT UNSIGNED NOT NULL,
	CONSTRAINT `fk_book_author`
		FOREIGN KEY (author_id) REFERENCES author (id)
		ON DELETE CASCADE
		ON UPDATE RESTRICT
) ENGINE = InnoDB;

Now, if we try to insert a book with a non-existing author, we will get an error:

INSERT INTO book (title, author_id) VALUES ('Necronomicon', 1);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`book`, CONSTRAINT `fk_book_author` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`) ON DELETE CASCADE)

The error is very descriptive.

Now, let's try to properly insert two authors and their books:

INSERT INTO author (name) VALUES ('Abdul Alhazred');
INSERT INTO book (title, author_id) VALUES ('Necronomicon', LAST_INSERT_ID());

INSERT INTO author (name) VALUES ('H.P. Lovecraft');
INSERT INTO book (title, author_id) VALUES
	('The call of Cthulhu', LAST_INSERT_ID()),
	('The colour out of space', LAST_INSERT_ID());

It worked!

Now, let's delete the second author. When we created the foreign key, we specified ON DELETE CASCADE. This should propagate the deletion, and make the deleted author's books disappear:

DELETE FROM author WHERE id = 2;

SELECT * FROM book;
+----+--------------+-----------+
| id | title        | author_id |
+----+--------------+-----------+
|  3 | Necronomicon |         1 |
+----+--------------+-----------+

We also specified ON UPDATE RESTRICT. This should prevent us from modifying an author's id (the column referenced by the foreign key) if a child row exists:

UPDATE author SET id = 10 WHERE id = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`book`, CONSTRAINT `fk_book_author` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`) ON DELETE CASCADE)

Comments

Comments loading...
Content reproduced on this site is the property of its respective owners, and this content is not reviewed in advance by MariaDB. The views, information and opinions expressed by this content do not necessarily represent those of MariaDB or any other party.