0

1452 Cannot add or update a child row错误的实例解释

在MySQL 3.23.44版本后,InnoDB引擎类型的表支持了外键约束,外键的使用条件:



1.两个表必须是 InnoDB表,MyISAM类型表不支持外键;



2.外键列必须建立了索引,MySQL 4.1.2以后的版本在建立外键时会自动创建索引,但如果在较早的版本则需要显示建立; 



3.外键关系的两个表的列必须是数据类型相似,也就是可以相互转换类型的列,比如int和tinyint可以,而int和char则不可以;



外键的好处是可以使得两张表建立一定关联关系,保证两个表中数据的一致性和实现一些级联操作;



外键的定义语法:

[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)

    REFERENCES tbl_name (index_col_name, ...)

    [ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]

    [ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]



该语法可以在 CREATE TABLE 和 ALTER TABLE 时使用,如果不指定CONSTRAINT symbol,MYSQL会自动生成一个名字。



ON DELETE、ON UPDATE表示事件触发限制,可设参数:

RESTRICT(限制外表中的外键改动)

CASCADE(跟随外键改动)

SET NULL(设空值)

SET DEFAULT(设默认值)

NO ACTION(无动作,默认的)





举个例子演示一下,创建lingdao和yuangong两个表,领导表是主键,员工表是外键:

建表:



CREATE TABLE lingdao (

id int(11) NOT NULL auto_increment,

  name varchar(64) default '',

  PRIMARY KEY  (id)

) ENGINE=InnoDB DEFAULT CHARSET='utf8';



CREATE TABLE yuangong (

  id int(11) NOT NULL auto_increment,

  lingdao_id int(11) default NULL,

  name varchar(64) default '',

PRIMARY KEY  (id),

KEY dage_id (lingdao_id),

CONSTRAINT yg_ibfk_1 FOREIGN KEY (lingdao_id) REFERENCES lingdao (id)

) ENGINE=InnoDB DEFAULT CHARSET='utf8';



插入个领导:


mysql> INSERT INTO lingdao(name) VALUES('张总');
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM lingdao;
+----+--------+
| id | name   |
+----+--------+
|  1 | 张总 |
+----+--------+
1 row in set (0.00 sec)

插入个员工:


mysql>INSERT INTO  yuangong(lingdao_id,name) VALUES(1,'跑腿小兵A');
Query OK, 1 row affected (0.02 sec)

mysql> SELECT * FROM yuangong;
+----+---------+--------------+
| id | lingdao_id | name         |
+----+---------+--------------+
|  1 |       1 | 跑腿小兵A|
+----+---------+--------------+

好,现在两个表中都有了数据,而且也建立了外键关系,下面来进行下面的两种操作:

  1. 把领导删除:

    
    mysql> DELETE FROM lingdao WHERE id=1;
    ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`jbsage`.`yuangong`, CONSTRAINT `yg_ibfk_1` FOREIGN KEY (`lingdao_id`) REFERENCES `lingdao` (`id`))
    
    

    提示:无法删除?因为外键约束存在,张总下面还有员工。如果要删除张总,必须先把yuangong表中的跑腿小兵A删除掉,才可以删除张总。可以分下面两步操作:

    删除员工表中的数据,

    
    mysql> DELETE FROM yuangong WHERE id = 1;
    Query OK, 1 row affected (0.00 sec)
    
    

再删除领导表中的数据


mysql> DELETE FROM lngidao WHERE id = 1;

Query OK, 1 row affected (0.00 sec)

注意:上面两个id都等于1,分别是两个表中不同的id。这只是为了演示,不要混淆了。如果是真正的开发过程可不都是这样。


2.插入一个新的女下属:


mysql> INSERT INTO  yuangong(lingdao_id,name) VALUES(2,'端茶小秘A');              
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`jbsage`.`yuangong`, CONSTRAINT `yg_ibfk_1` FOREIGN KEY (`lingdao_id`) REFERENCES `lingdao` (`id`))

小秘来了,但是没有领导啊,分给谁?不存在lingdao_id等于2的领导,这是一个无效的不存在的领导,所以不允许插入数据。



上面的两种情况,就是外键存在时的常见操作,这种约束的目的就保持了不同表中数据的一致性。



下面针对第一种情况,我们介绍一下外键的强大之处:

增加外键约束事件触发限制,首先移除之前的外键约束


mysql> ALTER TABLE yuangong drop foreign key yg_ibfk_1;
Query OK, 1 row affected (0.03 sec)
Records: 1  Duplicates: 0  Warnings: 0

重新再yuangong表上加上外键约束,这次增加事件触发限制 on delete cascade on update cascade;


mysql> ALTER TABLE yuangong add foreign key(lingdao_id) references lingdao(id) on delete cascade on update cascade; 
Query OK, 1 row affected (0.03 sec)
Records: 1  Duplicates: 0  Warnings: 0

再次尝试删掉张总:


mysql> DELETE FROM lingdao WHERE id=1;
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM lingdao;
Empty set (0.01 sec)

mysql> SELECT * FROM yuangong;
Empty set (0.00 sec)

可以看到,只是对lingdao表执行了一条DELETE操作,但是这回对应的员工表中张总的下属信息也被删除了,这就是on delete cascade!删除操作会自己的级联把主键和外键表中关联的数据一起删掉。





这里是已DELETE删除操作为例,UPDATE更新表的操作原理和过程也是类似的。