mysql外键(Foreign Key)的使用

Posted 芬乐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql外键(Foreign Key)的使用相关的知识,希望对你有一定的参考价值。

不建议用自动编号字段作为外键关系约束的字段。

不过,你要坚持这么用,当然也可以。

先追加主记录后,用select @@identity获取新追加的主表的id1,然后在追加子表时,用这个值作为子表id1的值

 

二、

.   主键和外键是相对于整个数据库来说的,总体来说就是要实现数据库的实体完整性、参照完整性等完整性的约束。并满足数据库规范化的要求 1NF、2NF...
对于一个表定义了一个主键,对于该表可以为通过该键唯一地表示表中的每一记录。外键是相对于表中的一个列给它的一个约束,一般是另一个表中的主键,该列的值必须在另一个表中出现。

由此可见,外键表示了两个关系之间的联系。以另一个关系的外键作主关键字的表被称为主表,具有此外键的表被称为主表的从表。外键又称作外关键字

外键的作用:

保持数据一致性,完整性,主要目的是控制存储在外键表中的数据。 使两张表形成关联,外键只能引用外表中的列的值!

, 好象不缺少一些关系数据库的基础知识.
简单的说, 在关系型数据库中的每一个表都具备这样的特点, 在同一个表中没有完全一致的两行数据, 当一行数据可以有少数几个属性确定的话,这几个属性就可以成为主键, 设立了表的主键之后,数据库系统会为主键的列建立索引和制约, 利用主键进行检索的速度是最快的.
如果有两个表AB, 他们之间存在着某种对应关系,这种关系可以是A中一行记录对应于B中的一行记录,也可以是A的一行记录对应于B的多行记录,还可以是A的多行对应于B的多行,在关系型数据库中, 这种对应关系也要做成关系表,下面就一对一, 一对多, 多对多几种情况来说明一下关系表
一对一
A(学号, 姓名)
B(学号, 学习成绩)
A是一份学生名单, 学号是主键
B是一份成绩单, 学号也是主键,这样两个表就是一对一的关系, 反映出这一关系的是学号, 如果把表A做为主表的话, 表B的学号就是外键了

一对多
A(班级, 人数)
B(学号, 姓名)
A是一份班级列表, 表B是一分学生名单,每个学生都属于某一个班级, 而一个班级可以有很多学生
为了表示这样的关系, 可以做一个关系表C(学号,班级) 其中,学号是主键, 这就保证了一对多的关系, 而学号和班级, 都是外键, 由于B,C

多对多
A(课程, 学分)
B(学号, 姓名)
A是一份课程表
B是份名单, 一个学生可以选多门课程,一门课程中也可以有很多学生, 为了反映这样的关系建立表C(课程,学号)其中课程和学号都是主键,这就保证了多对多的关系, 同时他们也是外键

作为外键的属性反映了主表中的某些属性, 因此其类型要和主表的对应属性一致才行
建立了外键之后会产生一致性的制约, 比如说, 在一对多的例子中, 不允许在关系表中出现主表中没有的学号或者是班级,

另外,对外键的更新和删除, 也就有了下面两种制约
- 级联, 当删除了主表的主键之后, 同时也删除关系表中的外键, 比如,删除了一对多的例子中删除了班级, 系统会自动删除关系表C中含有该班级的所有记录
- 制约, 只有当关系表中没有与该主键对应的外键时才允许删除该主键,再比如, 在一对多的例子中, 想删除某一班级的话,就必须先删除关系表C中所有含该班级的记录

外键的设立可以保证数据的对应关系避免因为错误操作而遭到破坏,同时, 外键也可以提示系统事先建立索引和结合操作的执行计划,从而提高结合计算的效率

  例如:

  a b 两个表

  a表中存有客户号,客户名称

  b表中存有每订个客户的单

  有了外键后

  你只能在确信b 表中没有客户x的订单后,才可以在a表中删除客户x

  建立外键的前提: 本表的列必须与外键类型相同(外键必须是外表主键)。

  指定主键关键字: foreign key(列名)

  引用外键关键字: references <外键表名>(外键列名)(被参考的表)

  事件触发限制: on delete和on update ,可设参数cascade(跟随外键改动), restrict(限制外表中的外键改动),set Null(设空值),set Default(设默认值),[默认]no action

  例如:

  outTable表 主键 id类型 int

  创建含有外键的表:

  create table temp(

  id int,

  name char(20),

  foreign key(id) references outTable(id) on delete cascade on update cascade);

  说明:把id列 设为外键 参照外表outTable的id列 当外键的值删除 本表中对应的列筛除 当外键的值改变 本表中对应的列值改变。

  建键几个原则:

  1、 为关联字段创建外键。

  2、 所有的键都必须唯一。

  3、避免使用复合键。

4、外键总是关联唯一的键字段。

在关系中所有表中具有相同含义的字段作为公共部分来连接不同表中的记录。外键可以是一对一的,一个表的记录只能与另一个表的一条记录连接,或者是一 对多的,一个表的记录与另一个表的多条记录连接。

mysql中“键”和“索引”的定义相同, 所以外键和主键一样也是索引的一种。不同的是MySQL会自动为所有表的主键进行索引,但是外键字段必须由用户进行明确的索引。这和一些封建思想比较沉重的家庭是一样的,外来的孩子(儿媳妇,倒插门女婿)一般都是不受重视的。

表间一对一关系示例:

有两张表,第一张表是记录公司有多少人,都有谁,也就是员工编号及员工姓名这些基本表。另一张表记录每个月发给用户多少工资,所谓工资表是也。

但是工资表里面不能以员工姓名为主键,同样要通过员工id,因为员工的姓名是可能重复的啊。部门经理叫张三,小弟也叫张三,那这俩张三的工资能一样吗?并且员工表里面的每个人都有工资,否则谁也不给你干活,且一个人只能有一份工资,否则老板也不同意了。所以员工表和工资表是通过员工id进行关联的一 对一关系。
/*建立员工表*/
create table employees (
id int(5) not null auto_increment ,
name varchar(8) not null,
primary key (id)
)
type=innodb;

/*
建立工资表
*/
create table payroll(
id int(5) not null,
emp_id int(5) not null,
name varchar(8) not null,
payroll float(4,2) not null,
primary key(id),
index emp_id (emp_id),
foreign key (emp_id) references employees (id)
)
type = innodb;

参照完整性:

当外键与另一个表的字段有关系,而且这种关系是惟一时,这个系统就称为处于参照完整性的状态。也就是说,如果一个字段在所有的表中只出现一次,而且每个表的这个字段的变化都会影响其他表,这就是存在参照完整性。

术语理解上可能不太方便,其实就是说要在有外键的表中保持所有数据的一致性。比如说“张三”离职了,在员工表里面肯定没有这个人了,可是如果在工资表里面还存在这个孩子,那么老大就会很生气的。

MySQL的外键只能在InnoDB表中使用:

MySQL对此一直持观望态度,它允许使用外键,但是为了完整性检验的目的,在除了InnoDB表类型之外的所有表类型中都忽略了这个功能。这可能有些怪异,实际上却非常正常:对于数据库的所有外键的每次插入、更新和删除后,进行完整性检查是一个耗费时间和资源的过程,它可能影响性能,特别是当处理 复杂的或者是缠绕的连接树时。因而,用户可以在表的基础上,选择适合于特定需求的最好结合。。

所以,如果需要更好的性能,并且不需要完整性检查,可以选择使用MyISAM表类型,如果想要在MySQL中根据参照完整性来建立表并且希望在此基 础上保持良好的性能,最好选择表结构为innoDB类型。

MySQL创建外键语法:

创建外键的语法是这样的:FOREIGN KEY (当前表的字段名)… REFERENCES参照表 (参照表的字段名)

foreign key (emp_id) references employees (id);的意思就是说当前表的emp_id字段是以employees的id字段为外键的。

注意事项:

关系中的所有表必须是innoDB表,在非InnoDB表中,MySQL将会忽略FOREIGN KEY…REFERENCES修饰符。
用于外键关系的字段必须在所有的参照表中进行明确地索引,InnoDB不能自动地创建索引。
在外键关系中,字段的数据类型必须相似,这对于大小和符号都必须匹配的整数类型尤其重要。
即使表存在外键约束,MySQL还允许我们删除表,并且不会产生错误(即使这样做可能会破坏更早创建的外键)
删除外键方法:

long long ago,人们只能通过删除表来删除外键。不过现在MySQL(在4.0.13及更高版本中)提供了一种从表中删除外键比较缓和的方法,缓和与否不太清楚,但是至少不再那么无耻。

ALTER TABLE table-name DROP FOREIGN KEY key-id;

这里有一个概念,这个外键的id是啥玩意?我们可以通过SHOW CREATE TABLE 命令来获得key-id的值。日后我们详细讨论这些内容,大家可以自行演示。

/*
显示建表结构语句,key-id为payroll_ibfk_1
*/
show create table payroll G
/*
*************************** 1. row ***************************
       Table: payroll
Create Table: CREATE TABLE `payroll` (
  `id` int(5) NOT NULL,
  `emp_id` int(5) NOT NULL,
  `name` varchar(8) NOT NULL,
  `payroll` float(4,2) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `emp_id` (`emp_id`),
  CONSTRAINT `payroll_ibfk_1` FOREIGN KEY (`emp_id`) REFERENCES `employees` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

*/
自动键更新和删除:

外键可以保证新插入的记录的完整性。但是,如果在REFERENCES从句中从已命名的表删除记录会怎样?在使用同样的值作为外键的辅助表中会发生什么?

很明显,那些记录也应该被删除,否则在数据库中就会有很多无意义的孤立记录。MySQL可能通过向FOREIGN KEY…REFERENCES修饰符添加一个ON DELETEON UPDATE子句简化任务,它告诉了数据库在这种情况如何处理孤立任务。

请注意,通过 ON UPDATE 和ON DELETE规则,设置MySQL能够实现自动操作时,如果键的关系没有设置好,可能会导致严重的数据破坏。例如,如果一系列的表通过外键关系和ON DELETE CASCADE规则连接时,任意一个主表的变化都会导致甚至只和原始删除有一些将要联系的记录在没有警告的情况下被删除。所以,我们在操作之前还是要检查这些规则的,操作之后还要再次检查。
 
 
 三、
 
在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(无动作,默认的)

搞个例子,简单演示一下使用,做dage和xiaodi两个表,大哥表是主键,小弟表是外键:
建表:

 1技术分享图片CREATE TABLE `dage` (
 2技术分享图片  `id` int(11NOT NULL auto_increment,
 3技术分享图片  `name` varchar(32default ‘‘,
 4技术分享图片  PRIMARY KEY  (`id`)
 5技术分享图片) ENGINE=InnoDB DEFAULT CHARSET=latin1;
 6技术分享图片
 7技术分享图片CREATE TABLE `xiaodi` (
 8技术分享图片  `id` int(11NOT NULL auto_increment,
 9技术分享图片  `dage_id` int(11default NULL,
10技术分享图片  `name` varchar(32default ‘‘,
11技术分享图片  PRIMARY KEY  (`id`),
12技术分享图片  KEY `dage_id` (`dage_id`),
13技术分享图片  CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`)
14技术分享图片) ENGINE=InnoDB DEFAULT CHARSET=latin1;

插入个大哥:
1技术分享图片mysql> insert into dage(name) values(铜锣湾);
2技术分享图片Query OK, 1 row affected (0.01 sec)
3技术分享图片mysql> select * from dage;
4技术分享图片+----+--------+
5技术分享图片| id | name   |
6技术分享图片+----+--------+
7技术分享图片|  1 | 铜锣湾 |
8技术分享图片+----+--------+
9技术分享图片1 row in set (0.00 sec)

插入个小弟:
1技术分享图片mysql> insert into xiaodi(dage_id,name) values(1,铜锣湾_小弟A);
2技术分享图片Query OK, 1 row affected (0.02 sec)
3技术分享图片
4技术分享图片mysql> select * from xiaodi;
5技术分享图片+----+---------+--------------+
6技术分享图片| id | dage_id | name         |
7技术分享图片+----+---------+--------------+
8技术分享图片|  1 |       1 | 铜锣湾_小弟A |
9技术分享图片+----+---------+--------------+

把大哥删除:
1技术分享图片mysql> delete from dage where id=1;
2技术分享图片ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`bstar/xiaodi`, CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`))


提示:不行呀,有约束的,大哥下面还有小弟,可不能扔下我们不管呀!

插入一个新的小弟:

1技术分享图片mysql> insert into xiaodi(dage_id,name) values(2,旺角_小弟A);              
2技术分享图片ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`bstar/xiaodi`, CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`))
3技术分享图片


提示:小子,想造反呀!你还没大哥呢!

把外键约束增加事件触发限制:

 1技术分享图片mysql> show create table xiaodi;
 2技术分享图片技术分享图片技术分享图片
 3技术分享图片  CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`)
 4技术分享图片技术分享图片技术分享图片
 5技术分享图片mysql> alter table xiaodi drop foreign key xiaodi_ibfk_1; 
 6技术分享图片Query OK, 1 row affected (0.04 sec)
 7技术分享图片Records: 1  Duplicates: 0  Warnings: 
 8技术分享图片mysql> alter table xiaodi add foreign key(dage_id) references dage(id) on delete cascade on update cascade;
 9技术分享图片Query OK, 1 row affected (0.04 sec)
10技术分享图片Records: 1  Duplicates: 0  Warnings: 0

再次试着把大哥删了:
1技术分享图片mysql> delete from dage where id=1;
2技术分享图片Query OK, 1 row affected (0.01 sec)
3技术分享图片
4技术分享图片mysql> select * from dage;
5技术分享图片Empty set (0.01 sec)
6技术分享图片
7技术分享图片mysql> select * from xiaodi;
8技术分享图片Empty set (0.00 sec)



得,这回对应的小弟也没了,没办法,谁让你跟我on delete cascade了呢!

例子说明的应该蛮清楚了吧,其他功能对应手册自己实践吧!

转至:https://blog.csdn.net/likika2012/article/details/9859903

以上是关于mysql外键(Foreign Key)的使用的主要内容,如果未能解决你的问题,请参考以下文章

MySQL中的外键(foreign key)

MySQL中的外键(foreign key)

mysql外键(Foreign Key)的使用

Mysql-外键foreign key

mysql启动和关闭外键约束的方法(FOREIGN_KEY_CHECKS)

MySQL外键约束-foreign key