一、主键和外键的作用


定义主键和外键主要是为了维护关系数据库的完整性,总结一下:


主键是能确定一条记录的唯一标识,比如,一条记录包括身份正号,姓名,年龄。身份证号是唯一能确定你这个人的,其他都可能有重复,所以,身份证号是主键。

外键用于与另一张表的关联。是能确定另一张表记录的字段,用于保持数据的一致性。比如,A表中的一个字段,是B表的主键,那他就可以是A表的外键。

二、主键、外键和索引的区别

定义:

  • 主键--唯一标识一条记录,不能有重复的,不允许为空
  • 外键--表的外键是另一表的主键, 外键可以有重复的, 可以是空值
  • 索引--该字段没有重复值,但可以有一个空值

作用:

  • 主键--用来保证数据完整性
  • 外键--用来和其他表建立联系用的
  • 索引--是提高查询排序的速度

个数:


  • 主键--主键只能有一个
  • 外键--一个表可以有多个外键
  • 索引--一个表可以有多个唯一索引



 三、创建外键的形式


1、创建表时添加


 [CONSTARINT 外键名称(一般格式:当前表_fk_主表)] FOREIGN KEY(外键列) PEFERENCES 主表(字段)



-- 将user1表的pId与省份表的id字段关联    
 
 

   mysql> CREATE TABLE IF NOT EXISTS user1( 
 
 
 

   -> id Int UNSIGNED AUTO_INCREMENT KEY, 
 
 
 

   -> username VARCHAR(20) NOT NULL, 
 
 
 

   -> pId TINYINT UNSIGNED, 
 
 
 

   -> FOREIGN KEY(pId) REFERENCES provinces(id) 
 
 
 

   -> ); 
 
 
 
-- 将user2表的pId与省份表的id字段关联,并起别名

   mysql> CREATE TABLE IF NOT EXISTS user2( 
 
 
 

       -> id Int UNSIGNED AUTO_INCREMENT KEY, 
 
 
 

       -> username VARCHAR(20) NOT NULL, 
 
 
 

       -> pId TINYINT UNSIGNED, 
 
 
 

       -> CONSTRAINT user2_fk_provinces FOREIGN KEY(pId) REFERENCES provinces(id) 
 
 
 

       -> ); 
 
 
 

   mysql> SHOW CREATE TABLE user2; 
 
 
 

   | user2 | CREATE TABLE `user2` ( 
 
 
 

     `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
 
 
 

     `username` varchar(20) NOT NULL, 
 
 
 

     `pId` tinyint(3) unsigned DEFAULT NULL, 
 
 
 

     PRIMARY KEY (`id`), 
 
 
 
  KEY `user2_fk_provinces` (`pId`), -- 自动添加索引
 
 
CONSTRAINT `user2_fk_provinces` FOREIGN KEY (`pId`) REFERENCES `provinces` (`id`) --添加外键
 
 

   ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | 
 
--外键存在的情况下插入数据

   mysql> INSERT user1(username,pId) VALUES('HAHA1',1); 
 
 
 

   mysql> INSERT user1(username,pId) VALUES('HAHA1',4); 
 
 
 
--当外键里没有对应记录时提出错误
 
 

   mysql> INSERT user1(username,pId) VALUES('HAHA1',6); 
 
 
 
 a foreign key



2、表创建后通过ALTER语句添加


ALTER TABLE tbl_name ADD CONSTRAINT 约束名称 FOREIGN KEY(字段) REFERENCES 主表(字段名称)


    


-- 添加外键
 
 

   mysql> ALTER TABLE user2 ADD CONSTRAINT user2_fk_provinces FOREIGN KEY(pId) REFERENCES provinces(id); 
 
 mysql> SHOW CREATE TABLE user2; 
 
 | user2 | CREATE TABLE `user2` ( 
 
   `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
 
   `username` varchar(20) NOT NULL, 
 
   `pId` tinyint(3) unsigned DEFAULT NULL, 
 
   PRIMARY KEY (`id`), 
 
   KEY `user2_fk_provinces` (`pId`), 
 
   CONSTRAINT `user2_fk_provinces` FOREIGN KEY (`pId`) REFERENCES `provinces` (`id`) 
 
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |



3、删除外键


ALTER TABLE tbl_name DROP FOREIGN KEY 约束名称;


-- 删除外键
 
 

   mysql> ALTER TABLE user2 DROP FOREIGN KEY user2_fk_provinces; 
 
 
 

   mysql> SHOW CREATE TABLE user2; 
 
 
 

   | user2 | CREATE TABLE `user2` ( 
 
 
 

     `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
 
 
 

     `username` varchar(20) NOT NULL, 
 
 
 

     `pId` tinyint(3) unsigned DEFAULT NULL, 
 
 
 

     PRIMARY KEY (`id`), 
 
 
 

     KEY `user2_fk_provinces` (`pId`) 
 
 
 

   ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |


四、创建外键需要注意的情况


1、父表和子表必须使用相同的存储引擎;禁止使用临时表


2、存储引擎只能使用INNODB


3、字表外键必须关联父表主键


4、外键列和参照列应具有相似的数据类型


5、外键列和参照列必须创建索引



五、操作父表时,子表操作规则


1、CASCADE :当父表update或者delete时,让子表级联操作


2、SET NULL:当父表update或者delete时,设置子表外键列为NULL,前提是此列没有NOT NULL约束


3、RESTRICT:拒绝对父表更新操作


4、NO ACTION:同RESTRICT



     ON UPDATE|ON DELETE CASCADE|SET NULL|RESTRICT|NO  ACTION


-- 建立级联操作
 
 

   mysql> ALTER TABLE user1 ADD CONSTRAINT user1_fk_provinces FOREIGN KEY(pId) REFERENCES provinces(id) ON DELETE CASCADE ON UPDATE CASCADE; 
 
 
 
-- 地址表插入一条数据
 
 

   mysql> INSERT provinces(pName) VALUES('广州'); 
 
 
 

   -- 向用户表插入一条数据 
 
 
 

   mysql> INSERT user1(username,pId) VALUES('HAHA1',6); 
 
 
 

   mysql> select * from provinces; 
 
 
 

   +----+-------+ 
 
 
 

   | id | pName | 
 
 
 

   +----+-------+ 
 
 
 

   |  4 | 上海  | 
 
 
 

   |  3 | 北京  | 
 
 
 

   |  1 | 山东  | 
 
 
 

   |  6 | 广州  | 
 
 
 

   |  2 | 河北  | 
 
 
 

   |  5 | 美国  | 
 
 
 

   +----+-------+ 
 
 
 

   mysql> SELECT * FROM user1; 
 
 
 

   +----+----------+------+ 
 
 
 

   | id | username | pId  | 
 
 
 

   +----+----------+------+ 
 
 
 

   |  1 | HAHA1    |    1 | 
 
 
 

   |  2 | HAHA1    |    4 | 
 
 
 

   |  4 | HAHA1    |    6 | 
 
 
 

   +----+----------+------+ 
 
 
 

   3 rows in set (0.00 sec) 
 
 
 
 
  
 
 

   -- 当删除父表的一个条记录时 
 
 
 

   mysql> DELETE FROM provinces WHERE id=6; 
 
 
 

   Query OK, 1 row affected (0.06 sec) 
 
 
 

   -- 父表记录已经删除 
 
 
 

   mysql> select * from provinces; 
 
 
 

   +----+-------+ 
 
 
 

   | id | pName | 
 
 
 

   +----+-------+ 
 
 
 

   |  4 | 上海  | 
 
 
 

   |  3 | 北京  | 
 
 
 

   |  1 | 山东  | 
 
 
 

   |  2 | 河北  | 
 
 
 

   |  5 | 美国  | 
 
 
 

   +----+-------+ 
 
 
 

   5 rows in set (0.00 sec) 
 
 
 

   -- 子表记录级联删除 
 
 
 

   mysql> SELECT * FROM user1; 
 
 
 

   +----+----------+------+ 
 
 
 

   | id | username | pId  | 
 
 
 

   +----+----------+------+ 
 
 
 

   |  1 | HAHA1    |    1 | 
 
 
 

   |  2 | HAHA1    |    4 | 
 
 
 

   +----+----------+------+ 
 
 
 

   2 rows in set (0.00 sec)