MySQL_第13章_约束
第13章_约束
1. 约束(constraint)概述
1.1 为什么需要约束
- 实体完整性(Entity Integrity) :例如,同一个表中,不能存在两条完全相同无法区分的记录
- 域完整性(Domain Integrity) :例如:年龄范围0-120,性别范围“男/女”
- 引用完整性(Referential Integrity) :例如:员工所在部门,在部门表中要能找到这个部门
- 用户自定义完整性(User-defined Integrity) :例如:用户名唯一、密码不能为空等,本部门 经理的工资不得高于本部门职工的平均工资的5倍。
1.2 什么是约束
1.3 约束的分类
- 根据约束数据列的限制,约束可分为:
- 单列约束:每个约束只约束一列
- 多列约束:每个约束可约束多列数据
- 根据约束的作用范围,约束可分为:
- 列级约束:只能作用在一个列上,跟在列的定义后面
- 表级约束:可以作用在多个列上,不与列一起,而是单独定义
位置 支持的约束类型 是否可以起约束名列级约束: 列的后面 语法都支持,但外键没有效果 不可以表级约束: 所有列的下面 默认和非空不支持,其他支持 可以(主键没有效果)
- 根据约束起的作用,约束可分为:
- NOT NULL 非空约束,规定某个字段不能为空
- UNIQUE 唯一约束,规定某个字段在整个表中是唯一的
- PRIMARY KEY 主键(非空且唯一)约束
- FOREIGN KEY 外键约束
- CHECK 检查约束
- DEFAULT 默认值约束
注意: MySQL不支持 check 约束,但可以使用 check 约束,而没有任何效果
- 查看某个表已有的约束
#information_schema 数据库名(系统库)#table_constraints 表名称(专门存储各个表的约束)SELECT * FROM information_schema .table_constraintsWHERE table_name = ' 表名称 ' ;
2. 非空约束
2.1 作用
2.2 关键字
2.3 特点
- 默认,所有的类型的值都可以是NULL,包括INT、FLOAT等数据类型
- 非空约束只能出现在表对象的列上,只能某个列单独限定非空,不能组合非空
- 一个表可以有很多列都分别限定了非空
- 空字符串''不等于NULL,0也不等于NULL
2.4 添加非空约束
CREATE TABLE 表名称 (字段名 数据类型 ,字段名 数据类型 NOT NULL ,字段名 数据类型 NOT NULL);
CREATE TABLE emp(id INT ( 10 ) NOT NULL ,NAME VARCHAR ( 20 ) NOT NULL ,sex CHAR NULL);
CREATE TABLE student(sid int ,sname varchar ( 20 ) not null ,tel char ( 11 ) ,cardid char ( 18 ) not null);
insert into student values ( 1 , ' 张三 ' , '13710011002' , '110222198912032545' ); # 成功insert into student values ( 2 , ' 李四 ' , '13710011002' , null ); # 身份证号为空ERROR 1048 ( 23000 ): Column 'cardid' cannot be nullinsert into student values ( 2 , ' 李四 ' , null , '110222198912032546' ); # 成功, tel 允许为空insert into student values ( 3 , null , null , '110222198912032547' ); # 失败ERROR 1048 ( 23000 ): Column 'sname' cannot be null
alter table 表名称 modify 字段名 数据类型 not null ;
ALTER TABLE empMODIFY sex VARCHAR ( 30 ) NOT NULL ;
alter table student modify sname varchar ( 20 ) not null ;
2.5 删除非空约束
alter table 表名称 modify 字段名 数据类型 NULL ; # 去掉 not null ,相当于修改某个非注解字段,该字段允许为空或alter table 表名称 modify 字段名 数据类型 ; # 去掉 not null ,相当于修改某个非注解字段,该字段允许为空
ALTER TABLE empMODIFY sex VARCHAR ( 30 ) NULL ;
ALTER TABLE empMODIFY NAME VARCHAR ( 15 ) DEFAULT 'abc' NULL ;
3. 唯一性约束
3.1 作用
3.2 关键字
3.3 特点
- 同一个表可以有多个唯一约束。
- 唯一约束可以是某一个列的值唯一,也可以多个列组合的值唯一。
- 唯一性约束允许列值为空。
- 在创建唯一约束的时候,如果不给唯一约束命名,就默认和列名相同。
3.4 添加唯一约束
create table 表名称 (字段名 数据类型 ,字段名 数据类型 unique ,字段名 数据类型 unique key ,字段名 数据类型);create table 表名称 (字段名 数据类型 ,字段名 数据类型 ,字段名 数据类型 ,[ constraint 约束名 ] unique key ( 字段名 ));
create table student(sid int ,sname varchar ( 20 ),tel char ( 11 ) unique ,cardid char ( 18 ) unique key);
CREATE TABLE t_course(cid INT UNIQUE ,cname VARCHAR ( 100 ) UNIQUE ,description VARCHAR ( 200 ));
CREATE TABLE USER (id INT NOT NULL ,NAME VARCHAR ( 25 ),PASSWORD VARCHAR ( 16 ),-- 使用表级约束语法CONSTRAINT uk_name_pwd UNIQUE (NAME, PASSWORD ));
表示用户名和密码组合不能重复
insert into student values ( 1 , ' 张三 ' , '13710011002' , '101223199012015623' );insert into student values ( 2 , ' 李四 ' , '13710011003' , '101223199012015624' );
mysql> select * from student;+-----+-------+-------------+--------------------+| sid | sname | tel | cardid |+-----+-------+-------------+--------------------+| 1 | 张三 | 13710011002 | 101223199012015623 || 2 | 李四 | 13710011003 | 101223199012015624 |+-----+-------+-------------+--------------------+2 rows in set ( 0.00 sec)
insert into student values ( 3 , ' 王五 ' , '13710011004' , '101223199012015624' ); # 身份证号重复ERROR 1062 ( 23000 ): Duplicate entry '101223199012015624' for key 'cardid'insert into student values ( 3 , ' 王五 ' , '13710011003' , '101223199012015625' );ERROR 1062 ( 23000 ): Duplicate entry '13710011003' for key 'tel'
# 字段列表中如果是一个字段,表示该列的值唯一。如果是两个或更多个字段,那么复合唯一,即多个字段的组合是唯一的# 方式 1 :alter table 表名称 add unique key ( 字段列表 );
# 方式 2 :alter table 表名称 modify 字段名 字段类型 unique ;
ALTER TABLE USERADD UNIQUE (NAME, PASSWORD );
ALTER TABLE USERADD CONSTRAINT uk_name_pwd UNIQUE (NAME, PASSWORD );
ALTER TABLE USERMODIFY NAME VARCHAR ( 20 ) UNIQUE ;
举例:
create table student(sid int primary key ,sname varchar ( 20 ),tel char ( 11 ) ,cardid char ( 18 ));
3.5 关于复合唯一约束
create table 表名称 (字段名 数据类型 ,字段名 数据类型 ,字段名 数据类型 ,unique key ( 字段列表 ) # 字段列表中写的是多个字段名,多个字段名用逗号分隔,表示那么是复合唯一,即多个字段的组合是唯一的);
# 学生表create table student(sid int , # 学号sname varchar ( 20 ), # 姓名tel char ( 11 ) unique key , # 电话cardid char ( 18 ) unique key # 身份证号);# 课程表create table course(cid int , # 课程编号cname varchar ( 20 ) # 课程名称);# 选课表create table student_course(id int ,sid int ,cid int ,score int ,unique key (sid,cid) # 复合唯一);
insert into student values ( 1 , ' 张三 ' , '13710011002' , '101223199012015623' ); # 成功insert into student values ( 2 , ' 李四 ' , '13710011003' , '101223199012015624' ); # 成功insert into course values ( 1001 , 'Java' ),( 1002 , 'MySQL' ); # 成功
mysql> select * from student;+-----+-------+-------------+--------------------+| sid | sname | tel | cardid |+-----+-------+-------------+--------------------+| 1 | 张三 | 13710011002 | 101223199012015623 || 2 | 李四 | 13710011003 | 101223199012015624 |+-----+-------+-------------+--------------------+2 rows in set ( 0.00 sec)mysql> select * from course;+------+-------+| cid | cname |+------+-------+| 1001 | Java || 1002 | MySQL |+------+-------+2 rows in set ( 0.00 sec)
insert into student_course values( 1 , 1 , 1001 , 89 ),( 2 , 1 , 1002 , 90 ),( 3 , 2 , 1001 , 88 ),( 4 , 2 , 1002 , 56 ); # 成功
mysql> select * from student_course;+----+------+------+-------+| id | sid | cid | score |+----+------+------+-------+| 1 | 1 | 1001 | 89 || 2 | 1 | 1002 | 90 || 3 | 2 | 1001 | 88 || 4 | 2 | 1002 | 56 |+----+------+------+-------+4 rows in set ( 0.00 sec)
insert into student_course values ( 5 , 1 , 1001 , 88 ); # 失败#ERROR 1062 (23000): Duplicate entry '1-1001' for key 'sid' 违反 sid-cid 的复合唯一
3.5 删除唯一约束
- 添加唯一性约束的列上也会自动创建唯一索引。
- 删除唯一约束只能通过删除唯一索引的方式删除。
- 删除时需要指定唯一索引名,唯一索引名就和唯一约束名一样。
- 如果创建唯一约束时未指定名称,如果是单列,就默认和列名相同;如果是组合列,那么默认和()中排在第一个的列名相同。也可以自定义唯一性约束名。
SELECT * FROM information_schema .table_constraints WHERE table_name = ' 表名 ' ; # 查看都有哪些约束
ALTER TABLE USERDROP INDEX uk_name_pwd;
注意:可以通过 show index from 表名称 ; 查看表的索引
4. PRIMARY KEY 约束
4.1 作用
4.2 关键字
4.3 特点
- 主键约束相当于唯一约束+非空约束的组合,主键约束列不允许重复,也不允许出现空值。
- 一个表最多只能有一个主键约束,建立主键约束可以在列级别创建,也可以在表级别上创建。
- 主键约束对应着表中的一列或者多列(复合主键)
- 如果是多列组合的复合主键约束,那么这些列都不允许为空值,并且组合的值不允许重复。
- MySQL的主键名总是PRIMARY,就算自己命名了主键约束名也没用。
- 当创建主键约束时,系统默认会在所在的列或列组合上建立对应的主键索引(能够根据主键查询的,就根据主键查询,效率更高)。如果删除主键约束了,主键约束对应的索引就自动删除了。
- 需要注意的一点是,不要修改主键字段的值。因为主键是数据记录的唯一标识,如果修改了主键的值,就有可能会破坏数据的完整性。
4.4 添加主键约束
create table 表名称 (字段名 数据类型 primary key , # 列级模式字段名 数据类型 ,字段名 数据类型);create table 表名称 (字段名 数据类型 ,字段名 数据类型 ,字段名 数据类型 ,[ constraint 约束名 ] primary key ( 字段名 ) # 表级模式);
create table temp(id int primary key ,name varchar ( 20 ));
mysql> desc temp;+-------+-------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------+-------------+------+-----+---------+-------+| id | int ( 11 ) | NO | PRI | NULL | || name | varchar ( 20 ) | YES | | NULL | |+-------+-------------+------+-----+---------+-------+2 rows in set ( 0.00 sec)
insert into temp values ( 1 , ' 张三 ' ); # 成功insert into temp values ( 2 , ' 李四 ' ); # 成功
mysql> select * from temp;+----+------+| id | name |+----+------+| 1 | 张三 || 2 | 李四 |+----+------+2 rows in set ( 0.00 sec)
insert into temp values ( 1 , ' 张三 ' ); # 失败ERROR 1062 ( 23000 ): Duplicate (重复) entry (键入,输入) '1' for key 'PRIMARY'insert into temp values ( 1 , ' 王五 ' ); # 失败ERROR 1062 ( 23000 ): Duplicate entry '1' for key 'PRIMARY'insert into temp values ( 3 , ' 张三 ' ); # 成功
mysql> select * from temp;+----+------+| id | name |+----+------+| 1 | 张三 || 2 | 李四 || 3 | 张三 |+----+------+3 rows in set ( 0.00 sec)
insert into temp values ( 4 , null ); # 成功insert into temp values ( null , ' 李琦 ' ); # 失败ERROR 1048 ( 23000 ): Column 'id' cannot be null
mysql> select * from temp;+----+------+| id | name |+----+------+| 1 | 张三 || 2 | 李四 || 3 | 张三 || 4 | NULL |+----+------+4 rows in set ( 0.00 sec)
# 演示一个表建立两个主键约束create table temp(id int primary key ,name varchar ( 20 ) primary key);ERROR 1068 ( 42000 ): Multiple (多重的) primary key defined (定义)
- 列级约束
CREATE TABLE emp4(id INT PRIMARY KEY AUTO_INCREMENT ,NAME VARCHAR ( 20 ));
- 表级约束
CREATE TABLE emp5(id INT NOT NULL AUTO_INCREMENT ,NAME VARCHAR ( 20 ),pwd VARCHAR ( 15 ),CONSTRAINT emp5_id_pk PRIMARY KEY (id));
ALTER TABLE 表名称 ADD PRIMARY KEY ( 字段列表 ); # 字段列表可以是一个字段,也可以是多个字段,如果是多个字段的话,是复合主键
ALTER TABLE student ADD PRIMARY KEY (sid);
ALTER TABLE emp5 ADD PRIMARY KEY (NAME,pwd);
4.5 关于复合主键
create table 表名称 (字段名 数据类型 ,字段名 数据类型 ,字段名 数据类型 ,primary key ( 字段名 1, 字段名 2) # 表示字段 1 和字段 2 的组合是唯一的,也可以有更多个字段);
# 学生表create table student(sid int primary key , # 学号sname varchar ( 20 ) # 学生姓名);# 课程表create table course(cid int primary key , # 课程编号cname varchar ( 20 ) # 课程名称);# 选课表create table student_course(sid int ,cid int ,score int ,primary key (sid,cid) # 复合主键);
insert into student values ( 1 , ' 张三 ' ),( 2 , ' 李四 ' );insert into course values ( 1001 , 'Java' ),( 1002 , 'MySQL' );
mysql> select * from student;+-----+-------+| sid | sname |+-----+-------+| 1 | 张三 || 2 | 李四 |+-----+-------+2 rows in set ( 0.00 sec)mysql> select * from course;+------+-------+| cid | cname |+------+-------+| 1001 | Java || 1002 | MySQL |+------+-------+2 rows in set ( 0.00 sec)
insert into student_course values ( 1 , 1001 , 89 ),( 1 , 1002 , 90 ),( 2 , 1001 , 88 ),( 2 , 1002 , 56 );
mysql> select * from student_course;+-----+------+-------+| sid | cid | score |+-----+------+-------+| 1 | 1001 | 89 || 1 | 1002 | 90 || 2 | 1001 | 88 || 2 | 1002 | 56 |+-----+------+-------+4 rows in set ( 0.00 sec)
insert into student_course values ( 1 , 1001 , 100 );ERROR 1062 ( 23000 ): Duplicate entry '1-1001' for key 'PRIMARY'
mysql> desc student_course;+-------+---------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------+---------+------+-----+---------+-------+| sid | int ( 11 ) | NO | PRI | NULL | || cid | int ( 11 ) | NO | PRI | NULL | || score | int ( 11 ) | YES | | NULL | |+-------+---------+------+-----+---------+-------+3 rows in set ( 0.00 sec)
- 再举例
CREATE TABLE emp6(id INT NOT NULL ,NAME VARCHAR ( 20 ),pwd VARCHAR ( 15 ),CONSTRAINT emp7_pk PRIMARY KEY (NAME,pwd));
4.6 删除主键约束
alter table 表名称 drop primary key;
ALTER TABLE student DROP PRIMARY KEY ;
ALTER TABLE emp5 DROP PRIMARY KEY ;
说明:删除主键约束,不需要指定主键名,因为一个表只有一个主键,删除主键约束后,非空还存在。
5. 自增列:AUTO_INCREMENT
5.1 作用
5.2 关键字
5.3 特点和要求
create table employee(eid int auto_increment ,ename varchar ( 20 ));# ERROR 1075 (42000): Incorrect table definition; there can be only one auto columnand it must be defined as a key
create table employee(eid int primary key ,ename varchar ( 20 ) unique key auto_increment);# ERROR 1063 (42000): Incorrect column specifier for column 'ename' 因为 ename 不是整数类型
5.4 如何指定自增约束
create table 表名称 (字段名 数据类型 primary key auto_increment ,字段名 数据类型 unique key not null ,字段名 数据类型 unique key ,字段名 数据类型 not null default 默认值 ,);create table 表名称 (字段名 数据类型 default 默认值 ,字段名 数据类型 unique key auto_increment ,字段名 数据类型 not null default 默认值 ,,primary key ( 字段名 ));
create table employee(eid int primary key auto_increment ,ename varchar ( 20 ));
mysql> desc employee;+-------+-------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+-------+-------------+------+-----+---------+----------------+| eid | int ( 11 ) | NO | PRI | NULL | auto_increment || ename | varchar ( 20 ) | YES | | NULL | |+-------+-------------+------+-----+---------+----------------+2 rows in set ( 0.00 sec)
alter table 表名称 modify 字段名 数据类型 auto_increment ;
create table employee(eid int primary key ,ename varchar ( 20 ));
alter table employee modify eid int auto_increment ;
mysql> desc employee;+-------+-------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+-------+-------------+------+-----+---------+----------------+| eid | int ( 11 ) | NO | PRI | NULL | auto_increment || ename | varchar ( 20 ) | YES | | NULL | |+-------+-------------+------+-----+---------+----------------+2 rows in set ( 0.00 sec)
5.5 如何删除自增约束
#alter table 表名称 modify 字段名 数据类型 auto_increment;# 给这个字段增加自增约束alter table 表名称 modify 字段名 数据类型 ; # 去掉 auto_increment 相当于删除
alter table employee modify eid int ;
mysql> desc employee;+-------+-------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------+-------------+------+-----+---------+-------+| eid | int ( 11 ) | NO | PRI | NULL | || ename | varchar ( 20 ) | YES | | NULL | |+-------+-------------+------+-----+---------+-------+2 rows in set ( 0.00 sec)
5.6 MySQL 8.0新特性—自增变量的持久化
CREATE TABLE test1(id INT PRIMARY KEY AUTO_INCREMENT);
INSERT INTO test1VALUES ( 0 ),( 0 ),( 0 ),( 0 );
mysql> SELECT * FROM test1;+----+| id |+----+| 1 || 2 || 3 || 4 |+----+4 rows in set ( 0.00 sec)
DELETE FROM test1 WHERE id = 4 ;
INSERT INTO test1 VALUES ( 0 );
mysql> SELECT * FROM test1;+----+| id |+----+| 1 || 2 || 3 || 5 |+----+4 rows in set ( 0.00 sec)
DELETE FROM test1 where id= 5 ;
INSERT INTO test1 values ( 0 );
mysql> SELECT * FROM test1;+----+| id |+----+| 1 || 2 || 3 || 4 |+----+4 rows in set ( 0.00 sec)
mysql> SELECT * FROM test1;+----+| id |+----+| 1 || 2 || 3 || 6 |+----+4 rows in set ( 0.00 sec)
6. FOREIGN KEY 约束
6.1 作用
6.2 关键字
6.3 主表和从表/父表和子表
6.4 特点
6.5 添加外键约束
create table 主表名称 (字段 1 数据类型 primary key ,字段 2 数据类型);create table 从表名称 (字段 1 数据类型 primary key ,字段 2 数据类型 ,[ CONSTRAINT < 外键约束名称 >] FOREIGN KEY (从表的某个字段 ) references 主表名 ( 被参考字段 ));#( 从表的某个字段 ) 的数据类型必须与主表名 ( 被参考字段 ) 的数据类型一致,逻辑意义也一样#( 从表的某个字段 ) 的字段名可以与主表名 ( 被参考字段 ) 的字段名一样,也可以不一样-- FOREIGN KEY: 在表级指定子表中的列-- REFERENCES: 标示在父表中的列
create table dept( # 主表did int primary key , # 部门编号dname varchar ( 50 ) # 部门名称);create table emp( # 从表eid int primary key , # 员工编号ename varchar ( 5 ), # 员工姓名deptid int , # 员工所在的部门foreign key (deptid) references dept(did) # 在从表中指定外键约束#emp 表的 deptid 和和 dept 表的 did 的数据类型一致,意义都是表示部门的编号);说明:( 1 )主表 dept 必须先创建成功,然后才能创建 emp 表,指定外键成功。( 2 )删除表时,先删除从表 emp ,再删除主表 dept
ALTER TABLE 从表名 ADD [ CONSTRAINT 约束名 ] FOREIGN KEY ( 从表的字段 ) REFERENCES 主表名 ( 被引用字段 ) [ on update xx][ on delete xx];
ALTER TABLE emp1ADD [ CONSTRAINT emp_dept_id_fk] FOREIGN KEY (dept_id) REFERENCES dept(dept_id);
create table dept(did int primary key , # 部门编号dname varchar ( 50 ) # 部门名称);create table emp(eid int primary key , # 员工编号ename varchar ( 5 ), # 员工姓名deptid int # 员工所在的部门);# 这两个表创建时,没有指定外键的话,那么创建顺序是随意
alter table emp add foreign key (deptid) references dept(did);
6.6 演示问题
create table dept(did int , # 部门编号dname varchar ( 50 ) # 部门名称);create table emp(eid int primary key , # 员工编号ename varchar ( 5 ), # 员工姓名deptid int , # 员工所在的部门foreign key (deptid) references dept(did));#ERROR 1215 (HY000): Cannot add foreign key constraint 原因是 dept 的 did 不是键列
create table dept(did int primary key , # 部门编号dname varchar ( 50 ) # 部门名称);create table emp(eid int primary key , # 员工编号ename varchar ( 5 ), # 员工姓名deptid char , # 员工所在的部门foreign key (deptid) references dept(did));#ERROR 1215 (HY000): Cannot add foreign key constraint 原因是从表的 deptid 字段和主表的 did 字段的数据类型不一致,并且要它俩的逻辑意义一致
create table dept(did int primary key , # 部门编号dname varchar ( 50 ) # 部门名称);create table emp(eid int primary key , # 员工编号ename varchar ( 5 ), # 员工姓名did int , # 员工所在的部门foreign key (did) references dept(did)#emp 表的 deptid 和和 dept 表的 did 的数据类型一致,意义都是表示部门的编号# 是否重名没问题,因为两个 did 在不同的表中);
create table dept(did int primary key , # 部门编号dname varchar ( 50 ) # 部门名称);create table emp(eid int primary key , # 员工编号ename varchar ( 5 ), # 员工姓名deptid int , # 员工所在的部门foreign key (deptid) references dept(did)#emp 表的 deptid 和和 dept 表的 did 的数据类型一致,意义都是表示部门的编号);
create table dept(did int primary key , # 部门编号dname varchar ( 50 ) # 部门名称);create table emp(eid int primary key , # 员工编号ename varchar ( 5 ), # 员工姓名deptid int , # 员工所在的部门foreign key (deptid) references dept(did)#emp 表的 deptid 和和 dept 表的 did 的数据类型一致,意义都是表示部门的编号);
insert into dept values ( 1001 , ' 教学部 ' );insert into dept values ( 1003 , ' 财务部 ' );insert into emp values ( 1 , ' 张三 ' , 1001 ); # 添加从表记录成功,在添加这条记录时,要求部门表有 1001 部门insert into emp values ( 2 , ' 李四 ' , 1005 ); # 添加从表记录失败ERROR 1452 ( 23000 ): Cannot add (添加) or update (修改) a child row : a foreign keyconstraint fails ( `atguigudb` . `emp` , CONSTRAINT `emp_ibfk_1` FOREIGN KEY ( `deptid` )REFERENCES `dept` ( `did` )) 从表 emp 添加记录失败,因为主表 dept 没有 1005 部门
mysql> select * from dept;+------+--------+| did | dname |+------+--------+| 1001 | 教学部 || 1003 | 财务部 |+------+--------+2 rows in set ( 0.00 sec)mysql> select * from emp;+-----+-------+--------+| eid | ename | deptid |+-----+-------+--------+| 1 | 张三 | 1001 |+-----+-------+--------+1 row in set ( 0.00 sec)
update emp set deptid = 1002 where eid = 1 ; # 修改从表失败ERROR 1452 ( 23000 ): Cannot add (添加) or update (修改) a child row (子表的记录) : aforeign key constraint fails (外键约束失败) ( `atguigudb` . `emp` , CONSTRAINT `emp_ibfk_1`FOREIGN KEY ( `deptid` ) REFERENCES `dept` ( `did` )) # 部门表 did 字段现在没有 1002 的值,所以员工表中不能修改员工所在部门 deptid 为 1002update dept set did = 1002 where did = 1001 ; # 修改主表失败ERROR 1451 ( 23000 ): Cannot delete (删除) or update (修改) a parent row (父表的记录) : aforeign key constraint fails ( `atguigudb` . `emp` , CONSTRAINT `emp_ibfk_1` FOREIGN KEY( `deptid` ) REFERENCES `dept` ( `did` )) # 部门表 did 的 1001 字段已经被 emp 引用了,所以部门表的 1001 字段就不能修改了。update dept set did = 1002 where did = 1003 ; # 修改主表成功 因为部门表的 1003 部门没有被 emp 表引用,所以可以修改delete from dept where did= 1001 ; # 删除主表失败ERROR 1451 ( 23000 ): Cannot delete (删除) or update (修改) a parent row (父表记录) : aforeign key constraint fails ( `atguigudb` . `emp` , CONSTRAINT `emp_ibfk_1` FOREIGN KEY( `deptid` ) REFERENCES `dept` ( `did` )) # 因为部门表 did 的 1001 字段已经被 emp 引用了,所以部门表的1001 字段对应的记录就不能被删除
- 添加了外键约束后,主表的修改和删除数据受约束
- 添加了外键约束后,从表的添加和修改数据受约束
- 在从表上建立外键,要求主表必须存在
- 删除主表时,要求从表从表先删除,或将从表中外键引用该主表的关系先删除
6.7 约束等级
- Cascade方式 :在父表上update/delete记录时,同步update/delete掉子表的匹配记录
- Set null方式 :在父表上update/delete记录时,将子表上匹配记录的列设为null,但是要注意子表的外键列不能为not null
- No action方式 :如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作
- Restrict方式 :同no action, 都是立即检查外键约束
- Set default方式 (在可视化工具SQLyog中可能显示空白):父表有变更时,子表将外键列设置成一个默认的值,但Innodb不能识别
create table dept(did int primary key , # 部门编号dname varchar ( 50 ) # 部门名称);create table emp(eid int primary key , # 员工编号ename varchar ( 5 ), # 员工姓名deptid int , # 员工所在的部门foreign key (deptid) references dept(did) on update cascade on delete set null# 把修改操作设置为级联修改等级,把删除操作设置为 set null 等级);
insert into dept values ( 1001 , ' 教学部 ' );insert into dept values ( 1002 , ' 财务部 ' );insert into dept values ( 1003 , ' 咨询部 ' );insert into emp values ( 1 , ' 张三 ' , 1001 ); # 在添加这条记录时,要求部门表有 1001 部门insert into emp values ( 2 , ' 李四 ' , 1001 );insert into emp values ( 3 , ' 王五 ' , 1002 );
mysql> select * from dept;mysql> select * from emp;
# 修改主表成功,从表也跟着修改,修改了主表被引用的字段 1002 为 1004 ,从表的引用字段就跟着修改为 1004 了mysql> update dept set did = 1004 where did = 1002 ;Query OK, 1 row affected ( 0.00 sec)Rows matched: 1 Changed : 1 Warnings : 0mysql> select * from dept;+------+--------+| did | dname |+------+--------+| 1001 | 教学部 || 1003 | 咨询部 || 1004 | 财务部 | # 原来是 1002 ,修改为 1004+------+--------+3 rows in set ( 0.00 sec)mysql> select * from emp;+-----+-------+--------+| eid | ename | deptid |+-----+-------+--------+| 1 | 张三 | 1001 || 2 | 李四 | 1001 || 3 | 王五 | 1004 | # 原来是 1002 ,跟着修改为 1004+-----+-------+--------+3 rows in set ( 0.00 sec)
# 删除主表的记录成功,从表对应的字段的值被修改为 nullmysql> delete from dept where did = 1001 ;Query OK, 1 row affected ( 0.01 sec)mysql> select * from dept;+------+--------+| did | dname | # 记录 1001 部门被删除了+------+--------+| 1003 | 咨询部 || 1004 | 财务部 |+------+--------+2 rows in set ( 0.00 sec)mysql> select * from emp;+-----+-------+--------+| eid | ename | deptid |+-----+-------+--------+| 1 | 张三 | NULL | # 原来引用 1001 部门的员工, deptid 字段变为 null| 2 | 李四 | NULL || 3 | 王五 | 1004 |+-----+-------+--------+3 rows in set ( 0.00 sec)
create table dept(did int primary key , # 部门编号dname varchar ( 50 ) # 部门名称);create table emp(eid int primary key , # 员工编号ename varchar ( 5 ), # 员工姓名deptid int , # 员工所在的部门foreign key (deptid) references dept(did) on update set null on delete cascade# 把修改操作设置为 set null 等级,把删除操作设置为级联删除等级);
insert into dept values ( 1001 , ' 教学部 ' );insert into dept values ( 1002 , ' 财务部 ' );insert into dept values ( 1003 , ' 咨询部 ' );insert into emp values ( 1 , ' 张三 ' , 1001 ); # 在添加这条记录时,要求部门表有 1001 部门insert into emp values ( 2 , ' 李四 ' , 1001 );insert into emp values ( 3 , ' 王五 ' , 1002 );
mysql> select * from dept;+------+--------+| did | dname |+------+--------+| 1001 | 教学部 || 1002 | 财务部 || 1003 | 咨询部 |+------+--------+3 rows in set ( 0.00 sec)mysql> select * from emp;+-----+-------+--------+| eid | ename | deptid |+-----+-------+--------+| 1 | 张三 | 1001 || 2 | 李四 | 1001 || 3 | 王五 | 1002 |+-----+-------+--------+3 rows in set ( 0.00 sec)
# 修改主表,从表对应的字段设置为 nullmysql> update dept set did = 1004 where did = 1002 ;Query OK, 1 row affected ( 0.00 sec)Rows matched: 1 Changed : 1 Warnings : 0mysql> select * from dept;+------+--------+| did | dname |+------+--------+| 1001 | 教学部 || 1003 | 咨询部 || 1004 | 财务部 | # 原来 did 是 1002+------+--------+3 rows in set ( 0.00 sec)mysql> select * from emp;+-----+-------+--------+| eid | ename | deptid |+-----+-------+--------+| 1 | 张三 | 1001 || 2 | 李四 | 1001 || 3 | 王五 | NULL | # 原来 deptid 是 1002 ,因为部门表 1002 被修改了, 1002 没有对应的了,就设置为null+-----+-------+--------+3 rows in set ( 0.00 sec)
# 删除主表的记录成功,主表的 1001 行被删除了,从表相应的记录也被删除了mysql> delete from dept where did= 1001 ;Query OK, 1 row affected ( 0.00 sec)mysql> select * from dept;+------+--------+| did | dname | # 部门表中 1001 部门被删除+------+--------+| 1003 | 咨询部 || 1004 | 财务部 |+------+--------+2 rows in set ( 0.00 sec)mysql> select * from emp;+-----+-------+--------+| eid | ename | deptid | # 原来 1001 部门的员工也被删除了+-----+-------+--------+| 3 | 王五 | NULL |+-----+-------+--------+1 row in set ( 0.00 sec)
create table dept(did int primary key , # 部门编号dname varchar ( 50 ) # 部门名称);create table emp(eid int primary key , # 员工编号ename varchar ( 5 ), # 员工姓名deptid int , # 员工所在的部门foreign key (deptid) references dept(did) on update cascade on delete cascade# 把修改操作设置为级联修改等级,把删除操作也设置为级联删除等级);
insert into dept values ( 1001 , ' 教学部 ' );insert into dept values ( 1002 , ' 财务部 ' );insert into dept values ( 1003 , ' 咨询部 ' );insert into emp values ( 1 , ' 张三 ' , 1001 ); # 在添加这条记录时,要求部门表有 1001 部门insert into emp values ( 2 , ' 李四 ' , 1001 );insert into emp values ( 3 , ' 王五 ' , 1002 );
mysql> select * from dept;+------+--------+| did | dname |+------+--------+| 1001 | 教学部 || 1002 | 财务部 || 1003 | 咨询部 |+------+--------+3 rows in set ( 0.00 sec)mysql> select * from emp;+-----+-------+--------+| eid | ename | deptid |+-----+-------+--------+| 1 | 张三 | 1001 || 2 | 李四 | 1001 || 3 | 王五 | 1002 |+-----+-------+--------+3 rows in set ( 0.00 sec)
# 修改主表,从表对应的字段自动修改mysql> update dept set did = 1004 where did = 1002 ;Query OK, 1 row affected ( 0.00 sec)Rows matched: 1 Changed : 1 Warnings : 0mysql> select * from dept;+------+--------+| did | dname |+------+--------+| 1001 | 教学部 || 1003 | 咨询部 || 1004 | 财务部 | # 部门 1002 修改为 1004+------+--------+3 rows in set ( 0.00 sec)mysql> select * from emp;+-----+-------+--------+| eid | ename | deptid |+-----+-------+--------+| 1 | 张三 | 1001 || 2 | 李四 | 1001 || 3 | 王五 | 1004 | # 级联修改+-----+-------+--------+3 rows in set ( 0.00 sec)
# 删除主表的记录成功,主表的 1001 行被删除了,从表相应的记录也被删除了mysql> delete from dept where did= 1001 ;Query OK, 1 row affected ( 0.00 sec)
mysql> select * from dept;+------+--------+| did | dname | #1001 部门被删除了+------+--------+| 1003 | 咨询部 || 1004 | 财务部 |+------+--------+2 rows in set ( 0.00 sec)mysql> select * from emp;+-----+-------+--------+| eid | ename | deptid | #1001 部门的员工也被删除了+-----+-------+--------+| 3 | 王五 | 1004 |+-----+-------+--------+1 row in set ( 0.00 sec)
6.8 删除外键约束
( 1 ) 第一步先查看约束名和删除外键约束SELECT * FROM information_schema .table_constraints WHERE table_name = ' 表名称 ' ; # 查看某个表的约束名ALTER TABLE 从表名 DROP FOREIGN KEY 外键约束名 ;( 2 )第二步查看索引名和删除索引。(注意,只能手动删除)SHOW INDEX FROM 表名称 ; # 查看某个表的索引名ALTER TABLE 从表名 DROP INDEX 索引名 ;
mysql> SELECT * FROM information_schema .table_constraints WHERE table_name = 'emp' ;mysql> alter table emp drop foreign key emp_ibfk_1;Query OK, 0 rows affected ( 0.02 sec)Records: 0 Duplicates: 0 Warnings : 0
mysql> show index from emp;mysql> alter table emp drop index deptid;Query OK, 0 rows affected ( 0.01 sec)Records: 0 Duplicates: 0 Warnings : 0mysql> show index from emp;
6.9 开发场景
6.10 阿里开发规范
7. CHECK 约束
7.1 作用
2、关键字
3、说明:MySQL 5.7 不支持
create table employee(eid int primary key ,ename varchar ( 5 ),gender char check ( ' 男 ' or ' 女 ' ));
insert into employee values ( 1 , ' 张三 ' , ' 妖 ' );
mysql> select * from employee;+-----+-------+--------+| eid | ename | gender |+-----+-------+--------+| 1 | 张三 | 妖 |+-----+-------+--------+1 row in set ( 0.00 sec)
- 再举例
CREATE TABLE temp(id INT AUTO_INCREMENT ,NAME VARCHAR ( 20 ),age INT CHECK (age > 20 ),PRIMARY KEY (id));
- 再举例
age tinyint check(age >20) 或 sex char(2) check(sex in(‘男’,’女’))
- 再举例
CHECK(height>=0 AND height<3)
8. DEFAULT约束
8.1 作用
8.2 关键字
8.3 如何给字段加默认值
create table 表名称 (字段名 数据类型 primary key ,字段名 数据类型 unique key not null ,字段名 数据类型 unique key ,字段名 数据类型 not null default 默认值 ,);create table 表名称 (字段名 数据类型 default 默认值 ,字段名 数据类型 not null default 默认值 ,字段名 数据类型 not null default 默认值 ,primary key ( 字段名 ),unique key ( 字段名 ));说明:默认值约束一般不在唯一键和主键列上加
create table employee(eid int primary key ,ename varchar ( 20 ) not null ,gender char default ' 男 ' ,tel char ( 11 ) not null default '' # 默认是空字符串)
mysql> desc employee;+--------+-------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+--------+-------------+------+-----+---------+-------+| eid | int ( 11 ) | NO | PRI | NULL | || ename | varchar ( 20 ) | NO | | NULL | || gender | char ( 1 ) | YES | | 男 | || tel | char ( 11 ) | NO | | | |+--------+-------------+------+-----+---------+-------+4 rows in set ( 0.00 sec)
insert into employee values ( 1 , ' 汪飞 ' , ' 男 ' , '13700102535' ); # 成功
mysql> select * from employee;+-----+-------+--------+-------------+| eid | ename | gender | tel |+-----+-------+--------+-------------+| 1 | 汪飞 | 男 | 13700102535 |+-----+-------+--------+-------------+1 row in set ( 0.00 sec)
insert into employee(eid,ename) values ( 2 , ' 天琪 ' ); # 成功
mysql> select * from employee;+-----+-------+--------+-------------+| eid | ename | gender | tel |+-----+-------+--------+-------------+| 1 | 汪飞 | 男 | 13700102535 || 2 | 天琪 | 男 | |+-----+-------+--------+-------------+2 rows in set ( 0.00 sec)
insert into employee(eid,ename) values ( 3 , ' 二虎 ' );#ERROR 1062 (23000): Duplicate entry '' for key 'tel'# 如果 tel 有唯一性约束的话会报错,如果 tel 没有唯一性约束,可以添加成功
CREATE TABLE myemp(id INT AUTO_INCREMENT PRIMARY KEY ,NAME VARCHAR ( 15 ),salary DOUBLE ( 10 , 2 ) DEFAULT 2000);
alter table 表名称 modify 字段名 数据类型 default 默认值 ;# 如果这个字段原来有非空约束,你还保留非空约束,那么在加默认值约束时,还得保留非空约束,否则非空约束就被删除了# 同理,在给某个字段加非空约束也一样,如果这个字段原来有默认值约束,你想保留,也要在 modify 语句中保留默认值约束,否则就删除了alter table 表名称 modify 字段名 数据类型 default 默认值 not null ;
create table employee(eid int primary key ,ename varchar ( 20 ),gender char ,tel char ( 11 ) not null);
mysql> desc employee;+--------+-------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+--------+-------------+------+-----+---------+-------+| eid | int ( 11 ) | NO | PRI | NULL | || ename | varchar ( 20 ) | YES | | NULL | || gender | char ( 1 ) | YES | | NULL | || tel | char ( 11 ) | NO | | NULL | |+--------+-------------+------+-----+---------+-------+4 rows in set ( 0.00 sec)
alter table employee modify gender char default ' 男 ' ; # 给 gender 字段增加默认值约束alter table employee modify tel char ( 11 ) default '' ; # 给 tel 字段增加默认值约束
mysql> desc employee;+--------+-------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+--------+-------------+------+-----+---------+-------+| eid | int ( 11 ) | NO | PRI | NULL | || ename | varchar ( 20 ) | YES | | NULL | || gender | char ( 1 ) | YES | | 男 | || tel | char ( 11 ) | YES | | | |+--------+-------------+------+-----+---------+-------+4 rows in set ( 0.00 sec)
alter table employee modify tel char ( 11 ) default '' not null ; # 给 tel 字段增加默认值约束,并保留非空约束
mysql> desc employee;+--------+-------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+--------+-------------+------+-----+---------+-------+| eid | int ( 11 ) | NO | PRI | NULL | || ename | varchar ( 20 ) | YES | | NULL | || gender | char ( 1 ) | YES | | 男 | || tel | char ( 11 ) | NO | | | |+--------+-------------+------+-----+---------+-------+4 rows in set ( 0.00 sec)
8.4 如何删除默认值约束
alter table 表名称 modify 字段名 数据类型 ; # 删除默认值约束,也不保留非空约束alter table 表名称 modify 字段名 数据类型 not null ; # 删除默认值约束,保留非空约束
alter table employee modify gender char ; # 删除 gender 字段默认值约束,如果有非空约束,也一并删除alter table employee modify tel char ( 11 ) not null ; # 删除 tel 字段默认值约束,保留非空约束
mysql> desc employee;+--------+-------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+--------+-------------+------+-----+---------+-------+| eid | int ( 11 ) | NO | PRI | NULL | || ename | varchar ( 20 ) | YES | | NULL | || gender | char ( 1 ) | YES | | NULL | || tel | char ( 11 ) | NO | | NULL | |+--------+-------------+------+-----+---------+-------+4 rows in set ( 0.00 sec)
9. 面试
MySQL_第13章_约束相关推荐
- Mysql 约束练习【第13章_约束】
#第13章_约束 /* 基础知识 1.1 为什么需要约束? 为了保证数据的完整性! 1.2 什么叫约束?对表中字段的限制. 1.3 约束的分类: 角度1:约束的字段的个数 单列约束 vs 多列约束 角 ...
- c语言程序设计实验13文件,第13章_文件---《C语言程序设计》实验指导.ppt
第13章_文件---<C语言程序设计>实验指导 第十三章 主要内容 13.1 C文件概述 13.2 文件类型指针 13.3 文件的打开与关闭 13.4 文件的读写 13.5 文件的定位 1 ...
- 明解C语言入门篇_第13章_文件处理
前言 本文为业余学习<明解C语言入门篇>的记录,包含代码清单和练习题. 开始学习时间:2022年8月21日 +++++++++++++++++++++++++++++++ 第1章 初识C语 ...
- PCL_第13章_重建
一.resamping重采样 参考:https://www.cnblogs.com/longyp/articles/7435547.html https://blog.csdn.net/DLW__/a ...
- 【山外笔记-计算机网络·第7版】第13章:计算机网络名词缩写汇总
本文下载链接: [学习笔记]第13章_计算机网络名词缩写汇总.pdf ACK:ACKnowledgement,确认 ADSL:Asymmetric Digital Subscriber Line,非对 ...
- 第13章 Kotlin 集成 SpringBoot 服务端开发(1)
第13章 Kotlin 集成 SpringBoot 服务端开发 本章介绍Kotlin服务端开发的相关内容.首先,我们简单介绍一下Spring Boot服务端开发框架,快速给出一个 Restful He ...
- 第5章_数据库相关(一)
第5章_数据库相关 1.CAP定理 2.事务的`ACID`特性 3.并发异常 4.隔离级别 5.`Oracle`.`MySQL`.`SQL Server`的事务隔离级别 6.范式(`Normal Fo ...
- Squid第13章 日志文件
原贴: 第13章 日志文件 13.1 cache.log 13.1.1 debug级别 13.1.2 转发cache.log消息到系统日志 13.1.3 dump cache.log消息到终端 13. ...
- c语言是非结构化程序设计语言,第章_结构化程序设计基础和C语言的控制结构(fb).ppt...
第章_结构化程序设计基础和C语言的控制结构(fb).ppt 2.4.2 continue语句 例2-24 编程序实现功能:检测从键盘上输入的以换行符结束的字符流,统计非字母字符的个数. 分析:通过循环 ...
最新文章
- java 复制对象有哪些方式
- 剑指offer:连续子数组的最大和
- python的位运算符
- Open Source的一些网站,自己收集来的
- php打印负载函数、Linux awk打印负载
- ASP.NET页面揭秘之页面生命周期
- 转:C# Interview Questions
- linux 修改文件名_Linux常用命令
- 计算机系统基础:文件的存取和存储空间管理知识笔记
- HoloLens 2开发:获取并渲染双手
- python读取指定路径txt文件-python读取txt文件并取其某一列数据的示例
- k3c最新官改非常稳定了_软件聚分享库APP最新版下载-软件聚分享库v1.0.0安卓版下载...
- 系统盘格式化数据恢复
- [Unity] 利用Culling Group实现LOD和剔除逻辑
- js 实现文件下载——文档流形式和本地文件下载——基础积累
- 科学家发现超时空传输能量的方法
- Linux通过系统函数设置系统时间
- PHP+Redis令牌桶算法 接口限流
- 21天学会Java之(Java SE第十三篇):网络编程、TCP/UDP通信
- 100款 ❤HTML5七夕情人节表白网页源码❤ HTML+CSS+JavaScript 【建议收藏】