0% found this document useful (0 votes)
173 views12 pages

Foreign Keys

MySQL only supports foreign keys when using InnoDB tables. Foreign keys require that the referenced column has an index and specify actions for deletes and updates. Examples show how to create tables with foreign keys that reference other tables and columns.

Uploaded by

bobseko
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
173 views12 pages

Foreign Keys

MySQL only supports foreign keys when using InnoDB tables. Foreign keys require that the referenced column has an index and specify actions for deletes and updates. Examples show how to create tables with foreign keys that reference other tables and columns.

Uploaded by

bobseko
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 12

Foreign keys.

Information
MySQL ONLY supports foreign keys when you use InnoDB tables.
Note: If you set FOREIGN KEY (..) you must also set INDEX(..). See examples below.

Foreign key constraints:

Constraint Description
When a row in the parent table is deleted, InnoDB will automatically delete
ON DELETE CASCADE
corresponding foreign key column in all matching rows in the child table.
When a row in the parent table is deleted, InnoDB will automatically set
ON DELETE SET NULL corresponding foreign key column in all matching rows in the child table to
NULL.
ON DELETE RESTRICT disallows a delete if an associated record still
ON DELETE RESTRICT
exists.
When a row in the parent table is updated, InnoDB will automatically update
ON UPDATE CASCADE corresponding foreign key column in all matching rows in the child table to
the same value.
When a row in the parent table is updated, InnoDB will automatically set
ON UPDATE SET NULL corresponding foreign key column in all matching rows in the child table to
NULL.
ON UPDATE RESTRICT disallows an update if an associated record still
ON UPDATE RESTRICT
exists.

Examples

CREATE TABLE country (


    countryid int NOT NULL AUTO_INCREMENT PRIMARY KEY,
    countrycode varchar(2) NOT NULL DEFAULT '',
    countryname varchar(80) NOT NULL DEFAULT '',
    UNIQUE (countryname)
) TYPE = INNODB;

CREATE TABLE user (


    userid int NOT NULL AUTO_INCREMENT PRIMARY KEY,
    username varchar(20) NOT NULL DEFAULT '',
    password char(32) binary NOT NULL DEFAULT '',
    firstname varchar(50) NOT NULL DEFAULT '',
    lastname varchar(50) NOT NULL DEFAULT '',
    countryid smallint NOT NULL,
    UNIQUE (username),
    INDEX(countryid),
    FOREIGN KEY (countryid) REFERENCES country(countryid) ON DELETE RESTRICT
    ON UPDATE CASCADE
) TYPE = INNODB;

CREATE TABLE books_bought (


    userid int NOT NULL,
    bookid int NOT NULL,
    INDEX(userid),
    FOREIGN KEY (userid) REFERENCES user(userid) ON DELETE CASCADE
    ON UPDATE CASCADE,
    INDEX(bookid),
    FOREIGN KEY (bookid) REFERENCES book(bookid) ON DELETE CASCADE
    ON UPDATE CASCADE
) TYPE = INNODB;

1
Using Foreign Keys
In MySQL, InnoDB tables support checking of foreign key constraints.
For non-InnoDB tables, REFERENCES tbl_name(col_name) clause has no actual effect.
It serves only as a comment to the column.
mysql> CREATE TABLE person (
    ->     id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    ->     name CHAR(60) NOT NULL,
    ->     PRIMARY KEY (id)
    -> );
Query OK, 0 rows affected (0.03 sec)

mysql>
mysql> CREATE TABLE shirt (
    ->     id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    ->     owner SMALLINT UNSIGNED NOT NULL REFERENCES person(id),
    ->     PRIMARY KEY (id)
    -> );
Query OK, 0 rows affected (0.03 sec)

mysql>
mysql> desc person;
+-------+----------------------+------+-----+---------+----------------+
| Field | Type                 | Null | Key | Default | Extra          |
+-------+----------------------+------+-----+---------+----------------+
| id    | smallint(5) unsigned | NO   | PRI | NULL    | auto_increment |
| name  | char(60)             | NO   |     |         |                |
+-------+----------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> desc shirt;
+-------+----------------------+------+-----+---------+----------------+
| Field | Type                 | Null | Key | Default | Extra          |
+-------+----------------------+------+-----+---------+----------------+
| id    | smallint(5) unsigned | NO   | PRI | NULL    | auto_increment |
| owner | smallint(5) unsigned | NO   |     |         |                |
+-------+----------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql>
mysql> drop table shirt;
Query OK, 0 rows affected (0.00 sec)

mysql> drop table person;
Query OK, 0 rows affected (0.02 sec)

mysql>
mysql>

One table with two foreign keys


mysql>
mysql> CREATE TABLE Books(
    ->    BookID SMALLINT NOT NULL PRIMARY KEY,
    ->    BookTitle VARCHAR(60) NOT NULL,
    ->    Copyright YEAR NOT NULL

2
    -> )
    -> ENGINE=INNODB;
Query OK, 0 rows affected (0.05 sec)

mysql>
mysql>
mysql> INSERT INTO Books VALUES (12786, 'Java',           1934),
    ->                          (13331, 'MySQL',          1919),
    ->                          (14356, 'PHP',            1966),
    ->                          (15729, 'PERL',           1932),
    ->                          (16284, 'Oracle',         1996),
    ->                          (17695, 'Pl/SQL',         1980),
    ->                          (19264, 'JavaScript',     1992),
    ->                          (19354, 'www.java2s.com', 1993);
Query OK, 8 rows affected (0.05 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql>
mysql>
mysql> CREATE TABLE Authors(
    ->    AuthID SMALLINT NOT NULL PRIMARY KEY,
    ->    AuthFN VARCHAR(20),
    ->    AuthMN VARCHAR(20),
    ->    AuthLN VARCHAR(20)
    -> )
    -> ENGINE=INNODB;
Query OK, 0 rows affected (0.05 sec)

mysql>
mysql>
mysql> INSERT INTO Authors VALUES (1006, 'H', 'S.', 'T'),
    ->                            (1007, 'J', 'C',  'O'),
    ->                            (1008, 'B', NULL, 'E'),
    ->                            (1009, 'R', 'M',  'R'),
    ->                            (1010, 'J', 'K',  'T'),
    ->                            (1011, 'J', 'G.', 'N'),
    ->                            (1012, 'A', NULL, 'P'),
    ->                            (1013, 'A', NULL, 'W'),
    ->                            (1014, 'N', NULL, 'A');
Query OK, 9 rows affected (0.03 sec)
Records: 9  Duplicates: 0  Warnings: 0

mysql>
mysql>
mysql> CREATE TABLE AuthorBook(
    ->    AuthID SMALLINT NOT NULL,
    ->    BookID SMALLINT NOT NULL,
    ->    PRIMARY KEY (AuthID, BookID),
    ->    FOREIGN KEY (AuthID) REFERENCES Authors (AuthID),
    ->    FOREIGN KEY (BookID) REFERENCES Books (BookID)
    -> )
    -> ENGINE=INNODB;
Query OK, 0 rows affected (0.05 sec)

mysql>
mysql>
mysql> INSERT INTO AuthorBook VALUES (1006, 14356),
    ->                               (1008, 15729),
    ->                               (1009, 12786),
    ->                               (1010, 17695),

3
    ->                               (1011, 15729),
    ->                               (1012, 19264),
    ->                               (1012, 19354),
    ->                               (1014, 16284);
Query OK, 8 rows affected (0.03 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql>
mysql>
mysql> select * from Authors;
+--------+--------+--------+--------+
| AuthID | AuthFN | AuthMN | AuthLN |
+--------+--------+--------+--------+
|   1006 | H      | S.     | T      |
|   1007 | J      | C      | O      |
|   1008 | B      | NULL   | E      |
|   1009 | R      | M      | R      |
|   1010 | J      | K      | T      |
|   1011 | J      | G.     | N      |
|   1012 | A      | NULL   | P      |
|   1013 | A      | NULL   | W      |
|   1014 | N      | NULL   | A      |
+--------+--------+--------+--------+
9 rows in set (0.00 sec)

mysql> select * from Books;
+--------+----------------+-----------+
| BookID | BookTitle      | Copyright |
+--------+----------------+-----------+
|  12786 | Java           |      1934 |
|  13331 | MySQL          |      1919 |
|  14356 | PHP            |      1966 |
|  15729 | PERL           |      1932 |
|  16284 | Oracle         |      1996 |
|  17695 | Pl/SQL         |      1980 |
|  19264 | JavaScript     |      1992 |
|  19354 | www.java2s.com |      1993 |
+--------+----------------+-----------+
8 rows in set (0.00 sec)

mysql> select * from AuthorBook;
+--------+--------+
| AuthID | BookID |
+--------+--------+
|   1009 |  12786 |
|   1006 |  14356 |
|   1008 |  15729 |
|   1011 |  15729 |
|   1014 |  16284 |
|   1010 |  17695 |
|   1012 |  19264 |
|   1012 |  19354 |
+--------+--------+
8 rows in set (0.00 sec)

mysql>
mysql>
mysql> SELECT BookTitle, AuthID FROM Books, AuthorBook;
+----------------+--------+
| BookTitle      | AuthID |

4
+----------------+--------+
| Java           |   1006 |
| MySQL          |   1006 |
| PHP            |   1006 |
| PERL           |   1006 |
| Oracle         |   1006 |
| Pl/SQL         |   1006 |
| JavaScript     |   1006 |
| www.java2s.com |   1006 |
| Java           |   1008 |
| MySQL          |   1008 |
| PHP            |   1008 |
| PERL           |   1008 |
| Oracle         |   1008 |
| Pl/SQL         |   1008 |
| JavaScript     |   1008 |
| www.java2s.com |   1008 |
| Java           |   1009 |
| MySQL          |   1009 |
| PHP            |   1009 |
| PERL           |   1009 |
| Oracle         |   1009 |
| Pl/SQL         |   1009 |
| JavaScript     |   1009 |
| www.java2s.com |   1009 |
| Java           |   1010 |
| MySQL          |   1010 |
| PHP            |   1010 |
| PERL           |   1010 |
| Oracle         |   1010 |
| Pl/SQL         |   1010 |
| JavaScript     |   1010 |
| www.java2s.com |   1010 |
| Java           |   1011 |
| MySQL          |   1011 |
| PHP            |   1011 |
| PERL           |   1011 |
| Oracle         |   1011 |
| Pl/SQL         |   1011 |
| JavaScript     |   1011 |
| www.java2s.com |   1011 |
| Java           |   1012 |
| MySQL          |   1012 |
| PHP            |   1012 |
| PERL           |   1012 |
| Oracle         |   1012 |
| Pl/SQL         |   1012 |
| JavaScript     |   1012 |
| www.java2s.com |   1012 |
| Java           |   1012 |
| MySQL          |   1012 |
| PHP            |   1012 |
| PERL           |   1012 |
| Oracle         |   1012 |
| Pl/SQL         |   1012 |
| JavaScript     |   1012 |
| www.java2s.com |   1012 |
| Java           |   1014 |
| MySQL          |   1014 |
| PHP            |   1014 |

5
| PERL           |   1014 |
| Oracle         |   1014 |
| Pl/SQL         |   1014 |
| JavaScript     |   1014 |
| www.java2s.com |   1014 |
+----------------+--------+
64 rows in set (0.00 sec)

mysql>
mysql> drop table AuthorBook;
Query OK, 0 rows affected (0.03 sec)

mysql> drop table Books;
Query OK, 0 rows affected (0.06 sec)

mysql> drop table Authors;
Query OK, 0 rows affected (0.05 sec)

4. 16. 7. FOREIGN KEY ON DELETE CASCADE ON UPDATE CASCAD


mysql>
mysql> CREATE TABLE Models
    -> (
    ->    ModelID SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    ->    Name VARCHAR(40) NOT NULL,
    ->    PRIMARY KEY (ModelID)
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql>
mysql> CREATE TABLE Orders
    -> (
    ->    ID          SMALLINT UNSIGNED NOT NULL PRIMARY KEY,
    ->    ModelID     SMALLINT UNSIGNED NOT NULL,
    ->    Description VARCHAR(40),
    ->    FOREIGN KEY (ModelID) REFERENCES Models (ModelID)
    ->       ON DELETE CASCADE ON UPDATE CASCADE
    -> );
Query OK, 0 rows affected (0.05 sec)

mysql>
mysql>
mysql> desc Models;
+---------+----------------------+------+-----+---------+----------------+
| Field   | Type                 | Null | Key | Default | Extra          |
+---------+----------------------+------+-----+---------+----------------+
| ModelID | smallint(5) unsigned | NO   | PRI | NULL    | auto_increment |
| Name    | varchar(40)          | NO   |     |         |                |
+---------+----------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql>
mysql> desc Orders;
+-------------+----------------------+------+-----+---------+-------+
| Field       | Type                 | Null | Key | Default | Extra |
+-------------+----------------------+------+-----+---------+-------+
| ID          | smallint(5) unsigned | NO   | PRI |         |       |
| ModelID     | smallint(5) unsigned | NO   | MUL |         |       |
| Description | varchar(40)          | YES  |     | NULL    |       |
6
+-------------+----------------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

mysql>
mysql> drop table Orders;
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> drop table Models;
Query OK, 0 rows affected (0.00 sec)

mysql>

13.6.4.4. FOREIGN KEY Constraints

InnoDB supports foreign key constraints. The syntax for a foreign key constraint definition in InnoDB looks like this:

[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

index_name represents a foreign key ID. If given, this is ignored if an index for the foreign key is defined explicitly. Otherwise, if InnoDB
creates an index for the foreign key, it uses index_name for the index name.

Foreign keys definitions are subject to the following conditions:

 Both tables must be InnoDB tables and they must not be TEMPORARY tables.
 Corresponding columns in the foreign key and the referenced key must have similar internal data types inside InnoDB so that
they can be compared without a type conversion. The size and sign of integer types must be the same. The length of string
types need not be the same. For nonbinary (character) string columns, the character set and collation must be the same.
 InnoDB 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. (This is in contrast to some
older versions, in which indexes had to be created explicitly or the creation of foreign key constraints would fail.) index_name, if
given, is used as described previously.
 InnoDB allows a foreign key to reference any index column or group of columns. However, in the referenced table, there must
be an index where the referenced columns are listed as the first columns in the same order.
 Index prefixes on foreign key columns are not supported. One consequence of this is that BLOB and TEXT columns cannot
be included in a foreign key because indexes on those columns must always include a prefix length.
 If the CONSTRAINT symbol clause is given, the symbol value must be unique in the database. If the clause is not given,
InnoDB creates the name automatically.

InnoDB rejects any INSERT or UPDATE operation that attempts to create a foreign key value in a child table if there is no a matching
candidate key value in the parent table. The action InnoDB takes for any UPDATE or DELETE operation that attempts to update or
delete a candidate key value in the parent table that has some matching rows in the child table is dependent on the referential action
specified using ON UPDATE and ON DELETE subclauses of the FOREIGN KEY clause. When the user attempts to delete or update
a row from a parent table, and there are one or more matching rows in the child table, InnoDB supports five options regarding the
action to be taken. If ON DELETE or ON UPDATE are not specified, the default action is RESTRICT.

 CASCADE: Delete or update the row from the parent table and automatically delete or update the matching rows in the child
table. Both ON DELETE CASCADE and ON UPDATE CASCADE are supported. Between two tables, you should not define
several ON UPDATE CASCADE clauses that act on the same column in the parent table or in the child table.

7
Note

Currently, cascaded foreign key actions to not activate triggers.

 SET NULL: Delete or update the row from the parent table and set the foreign key column or columns in the child table to
NULL. This is valid only if the foreign key columns do not have the NOT NULL qualifier specified. Both ON DELETE SET
NULL and ON UPDATE SET NULL clauses are supported.

If you specify a SET NULL action, make sure that you have not declared the columns in the child table as NOT NULL.

 NO ACTION: In standard SQL, NO ACTION means no action in the sense that an attempt to delete or update a primary key
value is not allowed to proceed if there is a related foreign key value in the referenced table. InnoDB rejects the delete or
update operation for the parent table.
 RESTRICT: Rejects the delete or update operation for the parent table. Specifying RESTRICT (or NO ACTION) is the same
as omitting the ON DELETE or ON UPDATE clause. (Some database systems have deferred checks, and NO ACTION is a
deferred check. In MySQL, foreign key constraints are checked immediately, so NO ACTION is the same as RESTRICT.)
 SET DEFAULT: This action is recognized by the parser, but InnoDB rejects table definitions containing ON DELETE SET
DEFAULT or ON UPDATE SET DEFAULT clauses.

InnoDB supports foreign key references within a table. In these cases, “child table records” really refers to dependent records within the
same table.

Here is a simple example that relates parent and child tables through a single-column foreign key:

CREATE TABLE parent (id INT NOT NULL,


PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE child (id INT, parent_id INT,
INDEX par_ind (parent_id),
FOREIGN KEY (parent_id) REFERENCES parent(id)
ON DELETE CASCADE
) ENGINE=INNODB;

A more complex example in which a product_order table has foreign keys for two other tables. One foreign key references a two-
column index in the product table. The other references a single-column index in the customer table:

CREATE TABLE product (category INT NOT NULL, id INT NOT NULL,
price DECIMAL,
PRIMARY KEY(category, id)) ENGINE=INNODB;
CREATE TABLE customer (id INT NOT NULL,
PRIMARY KEY (id)) ENGINE=INNODB;
CREATE TABLE product_order (no INT NOT NULL AUTO_INCREMENT,
product_category INT NOT NULL,
product_id INT NOT NULL,
customer_id INT NOT NULL,
PRIMARY KEY(no),
INDEX (product_category, product_id),
FOREIGN KEY (product_category, product_id)
REFERENCES product(category, id)
ON UPDATE CASCADE ON DELETE RESTRICT,
INDEX (customer_id),
FOREIGN KEY (customer_id)

8
REFERENCES customer(id)) ENGINE=INNODB;

InnoDB allows you to add a new foreign key constraint to a table by using ALTER TABLE:

ALTER TABLE tbl_name


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

The foreign key can be self referential (referring to the same table). When you add a foreign key constraint to a table using ALTER
TABLE, remember to create the required indexes first.

InnoDB supports the use of ALTER TABLE to drop foreign keys:

ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;

If the FOREIGN KEY clause included a CONSTRAINT name when you created the foreign key, you can refer to that name to drop the
foreign key. Otherwise, the fk_symbol value is internally generated by InnoDB when the foreign key is created. To find out the symbol
value when you want to drop a foreign key, use the SHOW CREATE TABLE statement. For example:

mysql> SHOW CREATE TABLE ibtest11c\G


*************************** 1. row ***************************
Table: ibtest11c
Create Table: CREATE TABLE `ibtest11c` (
`A` int(11) NOT NULL auto_increment,
`D` int(11) NOT NULL default '0',
`B` varchar(200) NOT NULL default '',
`C` varchar(175) default NULL,
PRIMARY KEY (`A`,`D`,`B`),
KEY `B` (`B`,`C`),
KEY `C` (`C`),
CONSTRAINT `0_38775` FOREIGN KEY (`A`, `D`)
REFERENCES `ibtest11a` (`A`, `D`)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `0_38776` FOREIGN KEY (`B`, `C`)
REFERENCES `ibtest11a` (`B`, `C`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB CHARSET=latin1
1 row in set (0.01 sec)

mysql> ALTER TABLE ibtest11c DROP FOREIGN KEY `0_38775`;

You cannot add a foreign key and drop a foreign key in separate clauses of a single ALTER TABLE statement. Separate statements
are required.

If ALTER TABLE for an InnoDB table results in changes to column values (for example, because a column is truncated), InnoDB's
FOREIGN KEY constraint checks do not notice possible violations caused by changing the values.

9
The InnoDB parser allows table and column identifiers in a FOREIGN KEY ... REFERENCES ... clause to be quoted within backticks.
(Alternatively, double quotes can be used if the ANSI_QUOTES SQL mode is enabled.) The InnoDB parser also takes into account the
setting of the lower_case_table_names system variable.

InnoDB returns a table's foreign key definitions as part of the output of the SHOW CREATE TABLE statement:

SHOW CREATE TABLE tbl_name;

mysqldump also produces correct definitions of tables in the dump file, and does not forget about the foreign keys.

You can also display the foreign key constraints for a table like this:

SHOW TABLE STATUS FROM db_name LIKE 'tbl_name';

The foreign key constraints are listed in the Comment column of the output.

When performing foreign key checks, InnoDB sets shared row-level locks on child or parent records it has to look at. InnoDB checks
foreign key constraints immediately; the check is not deferred to transaction commit.

To make it easier to reload dump files for tables that have foreign key relationships, mysqldump automatically includes a statement in the
dump output to set foreign_key_checks to 0. This avoids problems with tables having to be reloaded in a particular order when the dump
is reloaded. It is also possible to set this variable manually:

mysql> SET foreign_key_checks = 0;


mysql> SOURCE dump_file_name;
mysql> SET foreign_key_checks = 1;

This allows you to import the tables in any order if the dump file contains tables that are not correctly ordered for foreign keys. It also
speeds up the import operation. Setting foreign_key_checks to 0 can also be useful for ignoring foreign key constraints during LOAD
DATA and ALTER TABLE operations. However, even if foreign_key_checks = 0, InnoDB does not allow the creation of a foreign key
constraint where a column references a nonmatching column type. Also, if an InnoDB table has foreign key constraints, ALTER
TABLE cannot be used to change the table to use another storage engine. To alter the storage engine, you must drop any foreign key
constraints first.

InnoDB does not allow you to drop a table that is referenced by a FOREIGN KEY constraint, unless you do SET foreign_key_checks =
0. When you drop a table, the constraints that were defined in its create statement are also dropped.

If you re-create a table that was dropped, it must have a definition that conforms to the foreign key constraints referencing it. It must
have the right column names and types, and it must have indexes on the referenced keys, as stated earlier. If these are not satisfied,
MySQL returns error number 1005 and refers to error 150 in the error message.

If MySQL reports an error number 1005 from a CREATE TABLE statement, and the error message refers to error 150, table creation
failed because a foreign key constraint was not correctly formed. Similarly, if an ALTER TABLE fails and it refers to error 150, that
means a foreign key definition would be incorrectly formed for the altered table. You can use SHOW ENGINE INNODB STATUS to
display a detailed explanation of the most recent InnoDB foreign key error in the server.

Important

For users familiar with the ANSI/ISO SQL Standard, please note that no storage engine, including InnoDB, recognizes or enforces the
MATCH clause used in referential-integrity constraint definitions. Use of an explicit MATCH clause will not have the specified effect,
and also causes ON DELETE and ON UPDATE clauses to be ignored. For these reasons, specifying MATCH should be avoided.

The MATCH clause in the SQL standard controls how NULL values in a composite (multiple-column) foreign key are handled when
comparing to a primary key. InnoDB essentially implements the semantics defined by MATCH SIMPLE, which allow a foreign key to
be all or partially NULL. In that case, the (child table) row containing such a foreign key is allowed to be inserted, and does not match
any row in the referenced (parent) table. It is possible to implement other semantics using triggers.

10
Additionally, MySQL and InnoDB require that the referenced columns be indexed for performance. 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 and NOT NULL keys.

Furthermore, InnoDB does not recognize or support “inline REFERENCES specifications” (as defined in the SQL standard) where the
references are defined as part of the column specification. InnoDB accepts REFERENCES clauses only when specified as part of a
separate FOREIGN KEY specification. For other storage engines, MySQL Server parses and ignores foreign key specifications.

Deviation from SQL standards: If there are several rows in the parent table that have the same referenced key value, InnoDB acts in
foreign key checks as if the other parent rows with the same key value do not exist. For example, if you have defined a RESTRICT type
constraint, and there is a child row with several parent rows, InnoDB does not allow the deletion of any of those parent rows.

InnoDB performs cascading operations through a depth-first algorithm, based on records in the indexes corresponding to the foreign
key constraints.

Deviation from SQL standards: A FOREIGN KEY constraint that references a non-UNIQUE key is not standard SQL. It is an InnoDB
extension to standard SQL.

Deviation from SQL standards: If ON UPDATE CASCADE or ON UPDATE SET NULL recurses to update the same table it has
previously updated during the cascade, it acts like RESTRICT. This means that you cannot use self-referential ON UPDATE
CASCADE or ON UPDATE SET NULL operations. This is to prevent infinite loops resulting from cascaded updates. A self-referential
ON DELETE SET NULL, on the other hand, is possible, as is a self-referential ON DELETE CASCADE. Cascading operations may not
be nested more than 15 levels deep.

Deviation from SQL standards: Like MySQL in general, in an SQL statement that inserts, deletes, or updates many rows, InnoDB
checks UNIQUE and FOREIGN KEY constraints row-by-row. According to the SQL standard, the default behavior should be deferred
checking. That is, constraints are only checked after the entire SQL statement has been processed. Until InnoDB implements deferred
constraint checking, some things will be impossible, such as deleting a record that refers to itself via a foreign key.

Previous / Next / Up / Table of Contents

User Comments

Posted by Dennis Haney on July 15 2003 10:26am [Delete] [Edit]

For those encountering the problem " ERROR 1216: Cannot add or update a child row: a foreign key constraint fails", it actually means what it says!
Some row in the child does not comply with the constraint, correct the problem.
You find the rows like this:
select child.id from child left join parent on (child.parent_id=parent.id) where child.id is not null and parent.id is null;

Posted by Kai Baku on October 10 2003 11:09pm [Delete] [Edit]

There may be rare cases where circular dependencies would make sense. In the case of employees and store, you may have a circular dependency; in
which all employees must be stationed at a store, so the employees table will have storeID and EmployeeID attached as a concatonated primary key
(Presuming that an Employee can only have one store stationed) or even just a simple non-dependent foriegn key. Then each store must have a top
general manager in charge which is stationed there, so the store will have an EmployeeID Foreign Key to the store table to represent that the store has
that employee as the manager.

In this case, you have StoreID as an attribute of Employee, and EmployeeID (the Manager) as an attribute of Store.

While this works, it may not be the best method. There are likely better ways to handle such cases, but if your business rules requires such circular
dependencies, then it happens.

Also, it is interesting to note that while this query works (Note the PRIMARY KEY line):

CREATE TABLE `ffxi_characterJob` (


`serverID` int(11) NOT NULL,
`userid` int(10)unsigned NOT NULL,
11
`characterName` varchar(255) NOT NULL,
`jobAbbr` char(4) NOT NULL,
`jobLevel` int(11) default '0',
PRIMARY KEY (`serverID`,`userid`,`characterName`,`jobAbbr`),
INDEX (`jobAbbr`),
CONSTRAINT FOREIGN KEY (`serverID`,`userid`,`characterName`) REFERENCES `ffxi_characters` (`serverID`,`userid`,`characterName`) ON
DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT FOREIGN KEY (`jobAbbr`) REFERENCES `ffxi_jobType` (`jobAbbr`) ON DELETE CASCADE ON UPDATE CASCADE
) TYPE=InnoDB;

This query will give you an error 1005 and errno 150:

CREATE TABLE `ffxi_characterJob` (


`serverID` int(11) NOT NULL,
`userid` int(10)unsigned NOT NULL,
`characterName` varchar(255) NOT NULL,
`jobAbbr` char(4) NOT NULL,
`jobLevel` int(11) default '0',
PRIMARY KEY (`jobAbbr`,`serverID`,`userid`,`characterName`),
INDEX (`jobAbbr`),
CONSTRAINT FOREIGN KEY (`serverID`,`userid`,`characterName`) REFERENCES `ffxi_characters` (`serverID`,`userid`,`characterName`) ON
DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT FOREIGN KEY (`jobAbbr`) REFERENCES `ffxi_jobType` (`jobAbbr`) ON DELETE CASCADE ON UPDATE CASCADE
) TYPE=InnoDB;

In order to make the second one work, you have to add:


INDEX (`serverID`,`userid`,`characterName`)
before the the foreign key is made.

12

You might also like