1. 程式人生 > 其它 >MySQL Error Code 1215: "Cannot add foreign key constraint"

MySQL Error Code 1215: "Cannot add foreign key constraint"

MySQL Error Code 1215: “Cannot add foreign key constraint”

對於這種看似簡單的報錯:

ERROR 1215 (HY000): Cannot add foreign key constraint

可能會有多種原因。

對於這種錯誤,最好的方法就是檢視show engine innodb status中的latest foreign key error部分的內容。

1.約束所引用的表或索引尚不存在(通常在載入轉儲時)

如何診斷:對父表執行show tables、或show create table檢視。如果返回1146錯誤,就表示表沒有被按照正確的順序建立表

如何解決:手動create table,建立缺失的表然後重新執行,或者臨時關閉外來鍵約束檢查。這在存在環形參照的情況尤其容易出現。只要簡單的執行:

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS; 
SET FOREIGN_KEY_CHECKS=0;  
SOURCE /backups/mydump.sql; -- restore your backup within THIS session
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;

示例:

mysql> CREATE TABLE child (
  ->   id INT(10) NOT NULL PRIMARY KEY,
  ->   parent_id INT(10),
  ->   FOREIGN KEY (parent_id) REFERENCES `parent`(`id`)
  -> ) ENGINE INNODB;
ERROR 1215 (HY000): Cannot add foreign key constraint

# We check for the parent table and is not there.
mysql> SHOW TABLES LIKE 'par%';
Empty set (0.00 sec)

# We go ahead and create the parent table (we’ll use the same parent table structure for all other example in this blogpost):
mysql> CREATE TABLE parent (
  ->   id INT(10) NOT NULL PRIMARY KEY,
  ->   column_1 INT(10) NOT NULL,
  ->   column_2 INT(10) NOT NULL,
  ->   column_3 INT(10) NOT NULL,
  ->   column_4 CHAR(10) CHARACTER SET utf8 COLLATE utf8_bin,
  ->   KEY column_2_column_3_idx (column_2, column_3),
  ->   KEY column_4_idx (column_4)
  -> ) ENGINE INNODB;
Query OK, 0 rows affected (0.00 sec)

# And now we re-attempt to create the child table
mysql> CREATE TABLE child (
  ->   id INT(10) NOT NULL PRIMARY KEY,drop table child;
  ->   parent_id INT(10),
  ->   FOREIGN KEY (parent_id) REFERENCES `parent`(`id`)
  -> ) ENGINE INNODB;
Query OK, 0 rows affected (0.01 sec)

2.約束引用中的表或索引濫用引號

如何診斷:檢查每個FOREIGN KEY宣告並確保物件限定符沒有引號,或者表有引號並且列名有一對單獨的引號。

如何解決:都不使用引號,或者將表和列名各自使用引號

示例:

# wrong; single pair of backticks wraps both table and column
ALTER TABLE child ADD FOREIGN KEY (parent_id) REFERENCES `parent(id)`;

# correct; one pair for each part
ALTER TABLE child ADD FOREIGN KEY (parent_id) REFERENCES `parent`(`id`);

# also correct; no backticks anywhere
ALTER TABLE child ADD FOREIGN KEY (parent_id) REFERENCES parent(id);

# also correct; backticks on either object (in case it’s a keyword)
ALTER TABLE child ADD FOREIGN KEY (parent_id) REFERENCES parent(`id`);

3.約束引用中的本地鍵、外部表或列有錯字

如何診斷:執行show tables、show columns進行比較

如何解決:找出並修復錯字

示例:

# wrong; Parent table name is ‘parent’
ALTER TABLE child ADD FOREIGN KEY (parent_id) REFERENCES pariente(id);

# correct
ALTER TABLE child ADD FOREIGN KEY (parent_id) REFERENCES parent(id);

4.約束中引用的列的型別或者長度與被引用的列不同

如何診斷:執行 SHOW CREATE TABLE parent檢查本來地的列和引用的列是否有相同的型別和長度

如何解決:修改ddl語句,使得二者相互匹配

示例:

# wrong; id column in parent is INT(10)
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
parent_id BIGINT(10) NOT NULL,
FOREIGN KEY (parent_id) REFERENCES `parent`(`id`)
) ENGINE INNODB;

# correct; id column matches definition of parent table
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
parent_id INT(10) NOT NULL,
FOREIGN KEY (parent_id) REFERENCES `parent`(`id`)
) ENGINE INNODB;

5.外部物件不是任何型別的key

如何診斷:執行 SHOW CREATE TABLE parent檢查被引用的部分指向的列

如何解決:確保key、或unique key、或primary key在父表上是存在的

示例:

# wrong; column_1 is not indexed in our example table
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
parent_column_1 INT(10),
FOREIGN KEY (parent_column_1) REFERENCES `parent`(`column_1`)
) ENGINE INNODB;

# correct; we first add an index and then re-attempt creation of child table
ALTER TABLE parent ADD INDEX column_1_idx(column_1);

# and then re-attempt creation of child table
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
parent_column_1 INT(10),
FOREIGN KEY (parent_column_1) REFERENCES `parent`(`column_1`)
) ENGINE INNODB;

6.外來鍵是多個列組成的主鍵或唯一鍵,而被引用的列不是最左側的列

如何診斷:show create table parent檢查references指向的列出現在多列索引的位置

如何解決:在父表上增加一個索引,滿足被引用的列是在索引的最左側

示例:

# wrong; column_3 only appears as the second part of an index on parent table
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
parent_column_3 INT(10),
FOREIGN KEY (parent_column_3) REFERENCES `parent`(`column_3`)
) ENGINE INNODB;

# correct; create a new index for the referenced column
ALTER TABLE parent ADD INDEX column_3_idx (column_3);

# then re-attempt creation of child
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
parent_column_3 INT(10),
FOREIGN KEY (parent_column_3) REFERENCES `parent`(`column_3`)
) ENGINE INNODB;

7.兩個表或列使用不同的字符集或排序規則

如何診斷:show create table 父表和子表的character set、collate定義是否一致

如何解決:修改表定義,一般是修改子表

示例:

# wrong; the parent table uses utf8/utf8_bin for charset/collation 
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
parent_column_4 CHAR(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci,
FOREIGN KEY (parent_column_4) REFERENCES `parent`(`column_4`)
) ENGINE INNODB;

# correct; edited DDL so COLLATE matches parent definition
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
parent_column_4 CHAR(10) CHARACTER SET utf8 COLLATE utf8_bin,
FOREIGN KEY (parent_column_4) REFERENCES `parent`(`column_4`)
) ENGINE INNODB;

8.父表使用的不是innodb引擎

如何診斷:show create table parent檢查引擎型別

如何解決:修改表定義

示例:

# wrong; the parent table in this example is MyISAM:
CREATE TABLE parent (
id INT(10) NOT NULL PRIMARY KEY
) ENGINE MyISAM;

# correct: we modify the parent’s engine
ALTER TABLE parent ENGINE=INNODB;

9.使用語法簡寫來引用外來鍵

如何診斷:檢查references部分是否只是包含了表名字

如何解決:修改表定義

示例:

# wrong; only parent table name is specified in REFERENCES
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
column_2 INT(10) NOT NULL,
FOREIGN KEY (column_2) REFERENCES parent
) ENGINE INNODB;

# correct; both the table and column are in the REFERENCES definition
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
column_2 INT(10) NOT NULL,
FOREIGN KEY (column_2) REFERENCES parent(column_2)
) ENGINE INNODB;

10.父表是分割槽表

如何診斷:檢查父表是否是分割槽表

如何解決:移除分割槽定義

示例:

    # wrong: the parent table we see below is using PARTITIONs
CREATE TABLE parent (
id INT(10) NOT NULL PRIMARY KEY
) ENGINE INNODB
PARTITION BY HASH(id)
PARTITIONS 6;

#correct: ALTER parent table to remove partitioning
ALTER TABLE parent REMOVE PARTITIONING;

11.引用的列是生成的虛擬列(5.7之後才會有)

如何診斷: SHOW CREATE TABLE parent檢查是否是虛擬列

如何解決:修改父表,將虛擬列變成真正的列

示例:

# wrong; this parent table has a generated virtual column
CREATE TABLE parent (
id INT(10) NOT NULL PRIMARY KEY,
column_1 INT(10) NOT NULL,
column_2 INT(10) NOT NULL,
column_virt INT(10) AS (column_1 + column_2) NOT NULL,
KEY column_virt_idx (column_virt)
) ENGINE INNODB;

# correct: make the column STORED so it can be used as a foreign key
ALTER TABLE parent DROP COLUMN column_virt, ADD COLUMN column_virt INT(10) AS (column_1 + column_2) STORED NOT NULL;

# And now the child table can be created pointing to column_virt
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
parent_virt INT(10) NOT NULL,
FOREIGN KEY (parent_virt) REFERENCES parent(column_virt)
) ENGINE INNODB;

12.為約束設定預設值

如何診斷:查看錶是否on delete、on update約束而設定的set default

如何解決:移除或修改set default語句

示例:

# wrong; the constraint action uses SET DEFAULT
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
parent_id INT(10) NOT NULL,
FOREIGN KEY (parent_id) REFERENCES parent(id) ON UPDATE SET DEFAULT
) ENGINE INNODB;        

# correct; there's no alternative to SET DEFAULT, removing or picking other is the corrective measure
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
parent_id INT(10) NOT NULL,
FOREIGN KEY (parent_id) REFERENCES parent(id)
) ENGINE INNODB;

13.對not null的列,設定set null約束

如何診斷:查看錶是否有not null約束

如何解決:如果表已經存在,使用alter、modify移除not null

示例:

# wrong; the constraint column uses NOT NULL
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
parent_id INT(10) NOT NULL,
FOREIGN KEY (parent_id) REFERENCES parent(id) ON UPDATE SET NULL
) ENGINE INNODB;        

# correct; make the parent_id column accept NULLs (i.e. remove the NOT NULL)
CREATE TABLE child (
id INT(10) NOT NULL PRIMARY KEY,
parent_id INT(10),
FOREIGN KEY (parent_id) REFERENCES parent(id) ON UPDATE SET NULL
) ENGINE INNODB;