MySQL中外键的定义、作用、添加和删除

1 简介

在实际开发的项目中,一个健壮数据库中的数据一定有很好的参照完整性。例如学生档案和成绩单两张表,如果成绩单中有张三的成绩,学生档案中张三的档案却被删除了,这样就会产生垃圾数据或者错误数据。为了保证数据的完整性,将两张表之间的数据建立关系,因此就需要在成绩表中添加外键约束。

2    外键的定义
外键是指引用另外一个表中的一列或多列数据,被引用的列应该具有主键约束或者唯一性约束。外键用来建立和加强两个表数据之间的连接。

3    材料准备
mysql> create table grade(
    -> id int(4) not null primary key,
    -> name varchar(36)
    -> );
Query OK, 0 rows affected (1.14 sec)
 
上表为班级表。

mysql> drop table student;
Query OK, 0 rows affected (0.41 sec)

mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| grade          |
+----------------+
1 row in set (0.00 sec)

mysql> create table student (
    -> sid int(4) not null primary key,
    -> sname varchar(36),
    -> gid int(4) not null
    -> );
Query OK, 0 rows affected (0.44 sec)
 
上述的代码片段则是首先删除在本数据库中的student表,然后创建student表。
首先建立两张表,student和grade,学生表中的gid是学生所在的班级id,是引入了班级表grade中的主键id。那么gid就可以作为表student表的外键。被引用的表,即表grade是主表,引用外键的表,即student,是从表。两个表是主从关系。表student用gid可以连接表grade中的信息,从而建立了两个表中的连接。
可以这么理解,外键即依赖关系,可以明确的声明表和表之间的关系额字段的参照关系,这种就叫做表和表之间声明了一个外键。

注意:引入外键之后,外键列只能插入参照列存在的值,参照列被参照的值不能被删除,这就保证了数据的参照完整性。

4    外键的添加和删除
4.1    添加外键
为表添加外键约束的语法格式如下:

alert table 表名 add constraint FK_ID foreign key(外键字段名) references 外表表名(主键字段名)
 
其中FK_ID为外键的名称,是随意的。
为表student添加外键约束,具体语句如下:

mysql> alter table student add constraint FK_ID foreign key gid references grade id;
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 'references grade id' at line 1
mysql> alter table student add constraint FK_ID foreign key (gid) references grade (id);
Query OK, 0 rows affected (1.27 sec)
 
语句执行成功后,使用DESC语句来查看学生表和班级表,查询结果如下:

mysql> desc grade;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(4)      | NO   | PRI | NULL    |       |
| name  | varchar(36) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.06 sec)

mysql> desc student;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| sid   | int(4)      | NO   | PRI | NULL    |       |
| sname | varchar(36) | YES  |     | NULL    |       |
| gid   | int(4)      | NO   | MUL | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
 
可以从上述的输出中看出表grade中id为主键,student表中gid为外键,但是结果不能明确的看出两个表之间的关系。在MySQL中可以用show create table来查看表的详细结构,具体语句如下:

mysql> show create table student;
+---------+------------------------------------------------------------
| Table   | Create Table
+---------+------------------------------------------------------------
| student | CREATE TABLE `student` (
  `sid` int(4) NOT NULL,
  `sname` varchar(36) DEFAULT NULL,
  `gid` int(4) NOT NULL,
  PRIMARY KEY (`sid`),
  KEY `FK_ID` (`gid`),
  CONSTRAINT `FK_ID` FOREIGN KEY (`gid`) REFERENCES `grade` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+---------+------------------------------------------------------------
1 row in set (0.06 sec)
 
4.2    验证外键的作用
mysql> insert into student (sid, sname, gid) values(1000, 'wusong', 123);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`student`, CONSTRAINT `FK_ID` FOREIGN KEY (`gid`) REFERENCES `grade` (`id`))
1
2
上述错误表示,若要向student中插入学生数据,则必须插入已经在grade中存在的gid值,实际意义就是要把新来的学生放入某个班级,则班级必须先存在。

mysql> insert grade values(10, '一班');
Query OK, 1 row affected (0.16 sec)

mysql> insert grade values(11, '二班');
Query OK, 1 r,ow affected (0.12 sec)

mysql> insert grade values('', 1);
ERROR 1366 (HY000): Incorrect integer value: '' for column 'id' at row 1
mysql> insert grade values(12, 1);  //可见整数1可以自动转换为varchar1
Query OK, 1 row affected (0.09 sec)
mysql> select * from grade;
+----+--------+
| id | name   |
+----+--------+
| 10 | 一班   |
| 11 | 二班   |
| 12 | 1      |
+----+--------+
3 rows in set (0.00 sec)
 
通过插入语句,已经向grade中插入了三个班级。向班级1中插入数据和班级2中插入。学生记录维持在表student中。

mysql> insert into student(sid, sname, gid) values(1000, '周华健', 10);
Query OK, 1 row affected (0.11 sec)

mysql> insert into student(sid, sname, gid) values(1001, '周芷若', 10);
Query OK, 1 row affected (0.17 sec)

mysql> insert into student(sid, sname, gid) values(1002, '周杰伦', 10);
Query OK, 1 row affected (0.19 sec)
以同样的方式向班级2中插入两条数据
mysql> insert into student(sid, sname, gid) values(10003, '赵云', 11), (10004, '赵子龙', 11);
Query OK, 2 rows affected (0.12 sec)
Records: 2  Duplicates: 0  Warnings: 0
 
可以插入gid不存在的班级吗?

mysql> insert into student(sid, sname, gid) values(10003, '赵云', 0);
ERROR 1062 (23000): Duplicate entry '10003' for key 'PRIMARY'
mysql> insert into student(sid, sname, gid) values(10004, '赵云', 0);
ERROR 1062 (23000): Duplicate entry '10004' for key 'PRIMARY'
mysql> insert into student(sid, sname, gid) values(10005, '赵云', 0);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`student`, CONSTRAINT `FK_ID` FOREIGN KEY (`gid`) REFERENCES `grade` (`id`))
 
上述的代码片段中演示了插入数据时外键所起的作用,那么删除时外键依然会外参照完整性提供保护。

mysql> select * from grade;
+----+--------+
| id | name   |
+----+--------+
| 10 | 一班   |
| 11 | 二班   |
| 12 | 1      |
+----+--------+
3 rows in set (0.00 sec)

mysql> select * from student;
+-------+-----------+-----+
| sid   | sname     | gid |
+-------+-----------+-----+
|  1000 | 周华健    |  10 |
|  1001 | 周芷若    |  10 |
|  1002 | 周杰伦    |  10 |
| 10003 | 赵云      |  11 |
| 10004 | 赵子龙    |  11 |
+-------+-----------+-----+
5 rows in set (0.00 sec)
 
如果此时要直接删除grade中的班级1会发生什么?

mysql> delete from grade where id=10;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`student`, CONSTRAINT `FK_ID` FOREIGN KEY (`gid`) REFERENCES `grade` (`id`))
mysql> delete from grade where id=12;
Query OK, 1 row affected (0.16 sec)
 
上述代码片段id为10在删除记录时弹出了Error,而删除id为12的记录时可以成功执行,是因为在student表中有依赖id=10的记录存在,因此无法删除。

4.3    外键关联表联合删除
建立外键是为了保证数据的完整和统一性,但如果主表中的数据被删除或修改,从表中的数据该怎么办?很明显应该删除,否则数据库中会存在很多无意义的垃圾数据。为此,MySQL可以在建立外键时添加ON DELETE或ON UPDATE子句来告诉数据库,怎样避免垃圾数据的产生。

alter table 表名 add constraint FK_ID foreign key (外键字段名) references 外表表名 (主键字段名)
[on delete {cascade | set null | no action| restrict}]
[on update {cascade | set null | no action| restrict}]
 
其中restrict是默认操作,表示拒绝主表删除或修改外键关联列,这是最安全的设置。
而cascade表示删除包含与已删除键值有参考关系的所有记录。

4.4    删除外键约束
在实际开发中,根据业务逻辑的需求,需要解除两个表之间的关联关系时,就需要删除外键约束。删除外键约束的语法如下:

alter table 表名 drop foreign key 外键名;
1
如果解除student表的外键约束,具体语句如下:

mysql> show create table student;
+---------+--------------------------------------------------------------
| Table   | Create Table
+---------+--------------------------------------------------------------
| student | CREATE TABLE `student` (
  `sid` int(4) NOT NULL,
  `sname` varchar(36) DEFAULT NULL,
  `gid` int(4) NOT NULL,
  PRIMARY KEY (`sid`),
  KEY `FK_ID` (`gid`),
  CONSTRAINT `FK_ID` FOREIGN KEY (`gid`) REFERENCES `grade` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+---------+--------------------------------------------------------------
1 row in set (0.00 sec)

mysql> alter table student drop foreign key FK_ID;
Query OK, 0 rows affected (0.19 sec)
Records: 0  Duplicates: 0  Warnings: 0
 
此时表grade和student的参照关系便被移除了,

mysql> desc student;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| sid   | int(4)      | NO   | PRI | NULL    |       |
| sname | varchar(36) | YES  |     | NULL    |       |
| gid   | int(4)      | NO   | MUL | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> insert into student (sid, sname, gid) values (1003, '刘亦菲', 5);
Query OK, 1 row affected (0.13 sec)

mysql> delete from student where id=10;
ERROR 1054 (42S22): Unknown column 'id' in 'where clause'
mysql> delete from grade where id=10; //此时student表中存在gid为10的记录
Query OK, 1 row affected (0.13 sec)

mysql> show create table student;
+---------+------------------------------------------------------
| Table   | Create Table
+---------+------------------------------------------------------
| student | CREATE TABLE `student` (
  `sid` int(4) NOT NULL,
  `sname` varchar(36) DEFAULT NULL,
  `gid` int(4) NOT NULL,
  PRIMARY KEY (`sid`),
  KEY `FK_ID` (`gid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+---------+------------------------------------------------------
1 row in set (0.00 sec)

mysql> insert into student (sid, sname, grade^C
mysql> desc student;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| sid   | int(4)      | NO   | PRI | NULL    |       |
| sname | varchar(36) | YES  |     | NULL    |       |
| gid   | int(4)      | NO   | MUL | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
 
由于参照关系被移除了,则插入student表或者删除表grade记录则不再存在参照依赖关系了,由上述的代码片段可以看到结果。

5    总结
在多表查询中,外键是参照关系的提现,而明确的理解外键关系的含义,了解外键关系的添加和删除对于mysql数据库表之间的关系,对增强数据库表设计的理解,是程序员增强数据结构存储的必备知识储备。
 ———————————————— 
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/456496.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hive报错:Error: FUNCTION 'NUCLEUS_ASCII' already exists. (state=X0Y68,code=30000)

Hive执行schematool -initSchema -dbType derby报错。 报错的日志: doupeihuadoupeihua-2104 ~/software/hive/bin $ schematool -initSchema -dbType derbySLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/home/doupei…

Andorid Scrolling Activity(CoordinatorLayout详情)

1.new project -> Scrolling Activity 2.Layout xml code activity_scrolling.xml 1 <?xml version"1.0" encoding"utf-8"?>2 <android.support.design.widget.CoordinatorLayout xmlns:android"http://schemas.android.com/apk/res/an…

截取utf8中文字符串

英文直接截取即可。 中文应字节长度会乱码&#xff0c;应先转unicode截取。 如下&#xff1a; #-*- coding:utf8 -*- s u截取中文 s.decode(utf8)[0:3].encode(utf8)转载于:https://www.cnblogs.com/BigFishFly/p/6337183.html

解决:Navicat for mysql 设置外键出错

1 看下是不是外键允许为空&#xff0c;不唯一等约束条件不满足 2 或者外键设置删除时为 restrict 1. 两个字段的类型或者大小不严格匹配。例如&#xff0c;如果一个是int(10)&#xff0c;那么外键也必须设置成int(10)&#xff0c;而不是int(11)&#xff0c;也不能是tinyint。另…

Python加盐加密方法hashlib(md5,sha224,sha1,sha256)

用random.randint随机数给密码加,盐加强密码的安全性

Ubuntu16.04以root身份登入!

首先以非root用户身份登入系统。 1&#xff0c;修改root密码&#xff1a;启动shell&#xff0c;随后在shell里面输入命令&#xff1a; sudo passwd root 最后输入root要使用的密码&#xff0c;需要输入两次&#xff0c;这样root密码就修改完毕了&#xff01; 2&#xff0c;修改…

HDU2193-AVL-数据结构-AVL

题目链接&#xff1a;http://acm.hdu.edu.cn/statistic.php?pid2193&from126&lang&order_type0 好吧。水题一道&#xff0c;原本以为是一道写AVL树的想写来练练手。没有想到却是这样一道水题&#xff0c;好吧&#xff0c;猥琐的水过。 题目意思&#xff1a; 题目大…

玩Linux碰到的问题以及使用技巧总结

文章目录1、问题问题一&#xff1a;解压JDK报错&#xff1a;gzip:stdin:not in gzip format。 问题二&#xff1a;在Linux下ping不通外网 问题三&#xff1a;解决虚拟机克隆后网卡eth0不见的问题 问题四&#xff1a;执行脚本报错&#xff1a;syntax error: unexpected end of f…

python连接MySQL数据库搭建简易博客

实现功能大概 将python和MySQL数据库交互进行 封装 ---》》utils.py 文件程序 ----》blog.py # -*- coding: utf-8 -*- # Time : 2019/08/30 15:33 # Author : Liu # File : utils.pyimport pymysql import hashlibclass dbHelper:def __init__(self, host, user, pass…

利用Sqoop在数据库和Hive、HDFS之间做ETL操作

文章目录[toc] 目录&#xff1a;一、利用Sqoop&#xff0c;从Oracle到HDFS二、利用Sqoop&#xff0c;从Oracle到Hive三、遇到的问题目录&#xff1a; 一、利用Sqoop&#xff0c;从Oracle到HDFS 第一步&#xff1a;把Oracle驱动拷贝到Sqoop安装路径中的lib文件夹下。 第二步&…

跨地域的VPC私网互通【高速通道案例】

最近一家大型企业正在将业务迁移至阿里云平台&#xff0c;用户有深圳&#xff0c;北京&#xff0c;上海等分支&#xff0c;其中上海为总部&#xff0c;用户要求在阿里云上的华南1&#xff0c;华北2&#xff0c;华东2分别建立VPC网络&#xff0c;其中华南1&#xff0c;华北2要与…

HDU 1711 Number Sequence(KMP模板)

http://acm.hdu.edu.cn/showproblem.php?pid1711 这道题就是一个KMP模板。 1 #include<iostream> 2 #include<cstring>3 using namespace std;4 5 const int maxn 10000005;6 7 int n,m;8 9 int next[maxn]; 10 int a[maxn], b[maxn]; 11 12 void get_next() 13…

Redis数据库学习笔记

一、NoSql&#xff08;非关系型数据库&#xff09; NoSQL&#xff1a;NoSQL Not Only SQL 非关系型数据库 ​ NoSQL&#xff0c;泛指非关系型的数据库。随着互联网web2.0网站的兴起&#xff0c;传统的关系数据库在应付web2.0网站&#xff0c;特别是超大规模和高并发的SNS类型…

Sqoop的安装配置及工作机制

文章目录[toc] 目录&#xff1a;1、简介2、sqoop安装2.1、下载并解压2.2、修改配置文件2.3、加入mysql或oracle的jdbc驱动包2.4、验证启动3、Sqoop的原理3.1、代码定制目录&#xff1a; 1、简介 sqoop是apache旗下一款“Hadoop和关系数据库服务器之间传送数据”的工具。 导入…

3D打印技术在医疗领域能做些什么?帮助精确完成手术

3D打印技术出现在20世纪90年代中期。它与普通打印工作原理基本相同&#xff0c;打印机内装有液体或粉末等“打印材料”&#xff0c;与电脑连接后&#xff0c;通过电脑控制把“打印材料”一层层叠加起来&#xff0c;最终把计算机上的蓝图变成实物。这打印技术称为3D立体打印技术…

【一些简单的jQuery选择器】

学习【js DOM 编程艺术】&#xff0c;最后面有许多jQuery的选择器&#xff0c;每个都动手敲了一遍。 jQuery 提供了高级选择器的方法。 js获取元素的三个基本方法分别是通过标签名&#xff0c;类名和id&#xff0c;即(getElementsByTagName, getElementsByClassName和getElemen…

pymysql操作mysql数据库

一、pymysql操作mysql数据库 安装pymysql pip install pymysql 1.1 pymysql操作数据库的五行拳 连接数据库 使用Connect方法连接数据库 pymysql.Connections.Connection(hostNone, userNone, password, databaseNone, port0, charset) 参数说明&#xff1a;host – 数据库服务…

SecureCRT常用的使用技巧

文章目录前言&#xff1a;1、SecureCRT 超时自动断开连接的解决办法2、SecureCRT连接Linux时&#xff0c;终端显示乱码的问题。3、SecureCRT使用自动记录日志功能4、使用SecureCRT从Windows上传文件到Linux5、SecureCRT配色推荐和永久设置前言&#xff1a; 由于工作需要&#…

解决:(1062, Duplicate entry '2019-08-30' for key 'rdate')

解决(1062, "Duplicate entry 2019-08-30 for key rdate") 显然这个问题是因为插入重复主键导致从库不工作了&#xff0c;更改库的唯一限制&#xff1a; unique 为normal 或者删除unique ALTER TABLE 表明 DROP INDEX 字节名; 实例 CREATE TABLE good_booked (au…

人民币数字金额转大写金额

public class t {public static String Trans2RMB(String money) {int index money.indexOf(".");if (index < 0) {// 没有角分money money ".00";index money.indexOf(".");}if (money.substring(index, money.length()).length() < …