刚开始学数据库的时候,刚接触到的一个较为陌生的概念就是主键和外键。啥叫主键,从字面意思上来看感觉一脸懵。简单点说主键就类似每个人的身份证,代表一个唯一的某个人,而且主键不能为空,估计你也没见过哪个人没有身份证的。
那外键是啥,一个表中的某一个或多个字段是关联另一个表的主键,那我们把这一个或多个字段称为这个表的外键,外键可以是这个表的主键也可以不是。外键的作用是保证引用数据的完整性。
来看看书上是怎么定义主键的。主键:又称主码,是表中一列或多列的组合。下面来展示如何创建主键。
create table stu( id int PRIMARY KEY, name varchar(10), hobby varchar(20) );
Query OK, 0 rows affected (0.03 sec)
mysql> show create table stu;
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| stu | CREATE TABLE `stu` (
`id` int(11) NOT NULL,
`name` varchar(10) DEFAULT NULL,
`hobby` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
主键id显示的是NOT NULL,PRIMARY KEY (`id`)表明id是主键,上面是单字段主键。
mysql> create table stu1( id int , name varchar(10), hobby varchar(20),primary key(id,name) );
Query OK, 0 rows affected (0.02 sec)
mysql> show create table stu1;
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| stu1 | CREATE TABLE `stu1` (
`id` int(11) NOT NULL,
`name` varchar(10) NOT NULL,
`hobby` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`,`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql>
上面是多字段主键。
mysql> create table stu2( id int primary key, stu_id int, name varchar(20),constraint fk_stu foreign key(stu_id) references stu(id) );
Query OK, 0 rows affected (0.04 sec)
mysql>
mysql>
mysql> show create table stu2;
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| stu2 | CREATE TABLE `stu2` (
`id` int(11) NOT NULL,
`stu_id` int(11) DEFAULT NULL,
`name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_stu` (`stu_id`),
CONSTRAINT `fk_stu` FOREIGN KEY (`stu_id`) REFERENCES `stu` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql>
在表stu2上添加了fk_stu的外键约束,外键名称为stu_id,其依赖于表stu的主键id。下面来看外键保证引用数据的完整性 。
mysql> select * from stu2;
+----+--------+------+
| id | stu_id | name |
+----+--------+------+
| 1 | 1 | lisi |
+----+--------+------+
1 row in set (0.00 sec)
mysql> select * from stu;
+----+----------+-------+
| id | name | hobby |
+----+----------+-------+
| 1 | zhangdan | daqiu |
+----+----------+-------+
1 row in set (0.00 sec)
上面是2个表中的数据。表stu2的外键stu_id和stu的主键一一对应。现在再想表stu2中插入数据。
mysql> insert into stu2 values(1,2,"wangwu");
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
mysql>
插入记录报错了,因为表stu中没有id=2的记录。
mysql> insert into stu values(2,"wangwu","chifan");
Query OK, 1 row affected (0.00 sec)
mysql> select * from stu;
+----+----------+--------+
| id | name | hobby |
+----+----------+--------+
| 1 | zhangdan | daqiu |
| 2 | wangwu | chifan |
+----+----------+--------+
2 rows in set (0.00 sec)
mysql> insert into stu2 values(2,2,"zhaoliu");
Query OK, 1 row affected (0.00 sec)
mysql> select * from stu2;
+----+--------+---------+
| id | stu_id | name |
+----+--------+---------+
| 1 | 1 | lisi |
| 2 | 2 | zhaoliu |
+----+--------+---------+
2 rows in set (0.00 sec)
mysql>
我们先向表stu表插入id=2的字段,再对stu2操作就成功了。主表先动,从表才能动。从表是含有外键约束的那个表,主表就是那个含有外键约束对应主键的那个表。再想想,如果试着删除某一行会发生啥。
mysql> delete * from stu2 where id=2;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '* from stu2 where id=2' at line 1
mysql> delete * from stu where id=2;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '* from stu where id=2' at line 1
mysql>
不管对stu还是stu2进行删除操作都会失败,因为2个表已经有了约束关系,谁也离不开谁了。