Spec-Zone .ru
спецификации, руководства, описания, API
|
MySQL supports foreign keys, which let you cross-reference related data across tables, and foreign
key constraints, which help keep this spread-out data consistent. The essential syntax for a foreign key
constraint definition in a CREATE TABLE
or ALTER
TABLE
statement looks like this:
[CONSTRAINT [symbol
]] FOREIGN KEY [index_name
] (index_col_name
, ...) REFERENCEStbl_name
(index_col_name
,...) [ON DELETEreference_option
] [ON UPDATEreference_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 MySQL creates an index for the foreign key, it
uses index_name
for the index name.
Foreign keys definitions are subject to the following conditions:
Foreign key relationships involve a parent table that
holds the central data values, and a child table with identical values
pointing back to its parent. The FOREIGN KEY
clause is specified in the
child table. The parent and child tables must use the same storage engine. They must not be TEMPORARY
tables.
Corresponding columns in the foreign key and the referenced key must have similar data types. 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.
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. This
index might be silently dropped later, if you create another index that can be used to enforce the
foreign key constraint. index_name
, if given, is used as
described previously.
InnoDB
permits 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
clause is given, the symbol
symbol
value, if used, must be unique in
the database. A duplicate symbol
will result in an error
similar to: ERROR 1022 (2300): Can't write; duplicate key in table '#sql- 464_1'.
If the clause is not given, or a symbol
is not included
following the CONSTRAINT
keyword, a name for the constraint is created
automatically.
InnoDB
does not currently support foreign keys for tables with user-defined partitioning. This includes both
parent and child tables.
This restriction does not apply for NDB
tables that are partitioned by KEY
or LINEAR KEY
(the only user partitioning types supported by the NDB
storage engine); these may have foreign key references or be the
targets of such references.
This section describes how foreign keys help guarantee referential integrity.
For storage engines supporting foreign keys, MySQL 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.
When an UPDATE
or DELETE
operation affects a key value in the parent table that has matching
rows in the child table, the result depends on the referential action
specified using ON UPDATE
and ON DELETE
subclauses of
the FOREIGN KEY
clause. MySQL supports five options regarding the action to be
taken, listed here:
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, do not define several ON UPDATE CASCADE
clauses that act on the same column in the parent table or in the child table.
Currently, cascaded foreign key actions do 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
.
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
.
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.
NO ACTION
: A keyword from standard SQL. In MySQL,
equivalent to RESTRICT
. The MySQL Server rejects the delete or update
operation for the parent table if there is a related foreign key value in the referenced table. 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 MySQL
parser, but both InnoDB
and
NDB
reject table definitions containing ON
DELETE SET DEFAULT
or ON UPDATE SET DEFAULT
clauses.
For an ON DELETE
or ON UPDATE
that is not specified,
the default action is always RESTRICT
.
MySQL supports foreign key references between one column and another within a table. (A column cannot have a foreign key reference to itself.) 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), INDEX (customer_id), FOREIGN KEY (product_category, product_id) REFERENCES product(category, id) ON UPDATE CASCADE ON DELETE RESTRICT, FOREIGN KEY (customer_id) REFERENCES customer(id)) ENGINE=INNODB;
You can add a new foreign key constraint to an existing table by using ALTER TABLE
. The syntax relating to foreign keys for this statement is shown
here:
ALTER TABLEtbl_name
ADD [CONSTRAINT [symbol
]] FOREIGN KEY [index_name
] (index_col_name
, ...) REFERENCEStbl_name
(index_col_name
,...) [ON DELETEreference_option
] [ON UPDATEreference_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.
You can also use ALTER TABLE
to drop foreign keys, using the syntax shown here:
ALTER TABLEtbl_name
DROP FOREIGN KEYfk_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 generated internally when the foreign key is
created. To find out the symbol value when you want to drop a foreign key, use a SHOW CREATE TABLE
statement, as shown here:
mysql>SHOW CREATE TABLE ibtest11c\G
*************************** 1. row *************************** Table: ibtest11cCreate 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=latin11 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 the same ALTER TABLE
statement. A separate statements is required for each operation.
Before MySQL 5.6.7, using ALTER TABLE
to change the definition of a foreign key column could cause a loss
of referential integrity. For example, changing a foreign key column that contained NULL
values to be NOT NULL
caused the NULL
values to be the empty string. Similarly, an ALTER TABLE IGNORE
that removed rows in a parent table could break
referential integrity.
As of 5.6.7, the server prohibits changes to foreign key columns with the potential to cause loss of referential
integrity. A workaround is to use ALTER TABLE ...
DROP FOREIGN KEY
before changing the column definition and ALTER TABLE ... ADD FOREIGN KEY
afterward.
Table and column identifiers in a FOREIGN KEY ... REFERENCES ...
clause can be
quoted within backticks (`
). Alternatively, double quotation marks ("
) can be used if the ANSI_QUOTES
SQL mode is enabled. The setting of the lower_case_table_names
system variable is also taken into account.
You can view a child table's foreign key definitions as part of the output of the SHOW CREATE TABLE
statement:
SHOW CREATE TABLE tbl_name
;
You can also obtain information about foreign keys by querying the INFORMATION_SCHEMA.KEY_COLUMN_USAGE
table.
You can find information about foreign keys used by InnoDB
tables in the INNODB_SYS_FOREIGN
and INNODB_SYS_FOREIGN_COLS
tables, also in the INFORMATION_SCHEMA
database.
mysqldump produces correct definitions of tables in the dump file, including the foreign keys for child tables.
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
mysql>dump_file_name
;SET foreign_key_checks = 1;
This enables 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
, MySQL does not permit the creation of a foreign key
constraint where a column references a nonmatching column type. Also, if a table has foreign key constraints, ALTER TABLE
cannot be used to alter the table to use another storage engine.
To change the storage engine, you must drop any foreign key constraints first.
You cannot issue DROP TABLE
for a table that is referenced by a FOREIGN
KEY
constraint, unless you do SET foreign_key_checks = 0
. When you drop a
table, any constraints that were defined in the statement used to create that table 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 correct column names and types, and it must have indexes on the
referenced keys, as stated earlier. If these are not satisfied, MySQL returns Error 1005 and refers to Error 150
in the error message, which means that a foreign key constraint was not correctly formed. Similarly, if an ALTER TABLE
fails due to Error 150, this means that a foreign key definition
would be incorrectly formed for the altered table.
For InnoDB
tables, you can obtain a detailed explanation of the most recent InnoDB
foreign key error in the MySQL Server, by checking the output of SHOW
ENGINE INNODB STATUS
.
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. MySQL essentially implements the semantics defined by MATCH
SIMPLE
, which permit a foreign key to be all or partially NULL
. In
that case, the (child table) row containing such a foreign key is permitted to be inserted, and does not
match any row in the referenced (parent) table. It is possible to implement other semantics using triggers.
Additionally, MySQL requires that the referenced columns be indexed for performance reasons.
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.
Furthermore, MySQL 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. MySQL accepts REFERENCES
clauses only when specified as part of a separate FOREIGN KEY
specification.
For storage engines that do not support foreign keys (such as MyISAM
), MySQL Server parses and ignores foreign key specifications.