MYSQL约束

约束

约束CONSTRAINT概述

数据完整性DATA INTEGRITY是指数据的精确性ACCURACY和可靠性RELIABILITY。它是防止数据库中存在不符合语义规定的数据和以上因错误信息的输入输出造成无效操作或错误信息而提出的。

为了保证数据完整性,SQL规范以约束的方式对表数据进行额外的条件限制。从以下四个方面考虑:

  • 实体完整性(Entity Integrity) :例如,同一个表中,不能存在两条完全相同无法区分的记录
  • 域完整性(Domain Integrity) :例如:年龄范围0-120,性别范围“男/女”
  • 引用完整性(Referential Integrity) :例如:员工所在部门,在部门表中要能找到这个部门
  • 用户自定义完整性(User-defined Integrity) :例如:用户名唯一、密码不能为空等,本部门 经理的工资不得高于本部门职工的平均工资的5倍。
什么是约束

约束是对表中字段进行强制规定:

可以在创建表时,规定约束(通过CREATE TABLE语句),或者表创建之后通过ALTER TABLE语句规定约束

约束分类

根据约束数据列的限制,约束可分为

  • 单列约束:每个约束只约束一列
  • 多列约束:每个约束可约束多列数据

根据约束的作用范,约束可分为

  • 列级约束:只能作用在一个列上,跟在列的定义后面
  • 表级约束:可以使用在多个列上,不与列一起,而是单独定义

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IIjvjf4h-1649391420814)(E:\Typora笔记\java笔记\img\image-20220329155633700.png)]

根据约束起的作用,约束可分为:

  • NOT NULL:非空约束,规定某个字段不能为空

  • UNIQUE:唯一约束,规定某个字段在整个表中是唯一的

  • PRIMARY KEY:主键约束

  • FOREIGN KEY:外键约束

  • CHECK:检查约束

  • DEFAULT:默认值约束

    注意是:MYSQL7中不支持check约束,介可以使用check约束而没有任何效果

查看某个表中已有约束

#information_schema数据库名(系统库)
#table_constraints表名称(专门存储各个表的约束)
SELECT * FROM information_schema.table_constraints
WHERE table_name = '表名称';
非空约束

作用:限定某个字段、某列的值不允许为空

关键字:NOT NULL

特点:

  • 默认,所有类型的值都可以是NULL,包括INT , FLOAT等数据类型
  • 非空约束只能出现在表对象的列上,只能某个列单独限定非空,不能组合非空【就是只能作用字段的后面】
  • 一个表可以有很多列都分别限定了非空
  • 空字符串不能等于NULL,0也不等于NULL
添加非空约束

(1)建表时

CREATE TABLE 表名称(
字段名 数据类型,
字段名 数据类型 NOT NULL,
字段名 数据类型 NOT NULL
)

-- 非空约束
-- 创建表时 添加非空约束
CREATE TABLE test_null (
	id INT NOT NULL, -- 添加非空约束
	last_name VARCHAR(50), -- 添加非空约束
	email VARCHAR(50),
	salary DECIMAL(10,0) -- 一定要指定定点数,不然默认是 10,0
);

-- 向表中添加数据
INSERT INTO test_null(id,last_name,email,salary) 
VALUES (1,'haikang','haikang@qq3434',324324);

-- 报错:Column 'id' cannot be null 不能为null值
-- 就是添加了非空约束此字段不能为null值
INSERT INTO test_null(id,last_name,email,salary) 
VALUES (NULL,'haikang','haikang@qq3434',324324);

(2)创建表后添加非空约束

语法

alter table 表名称 modify 字段名 数据类型 not null;

案例

-- 查看表结构 
DESC test_null;
-- 创建表后,添加非空约束 两种方式
-- 给字段添加非空约束的前提,该字段不能存在有null值的记录
ALTER TABLE test_null MODIFY  last_name VARCHAR(50) NOT NULL;
ALTER TABLE test_null CHANGE email email VARCHAR(70) NOT NULL;

(3)删除非空约束

语法:

alter table 表名称 modify 字段名 数据类型 NULL;#去掉not null,相当于修改某个非注解字段,该字段允
许为空
或
alter table 表名称 modify 字段名 数据类型;#去掉not null,相当于修改某个非注解字段,该字段允许为空

案例

-- 删除非空约束
ALTER TABLE test_null MODIFY last_name VARCHAR(50);
ALTER TABLE test_null CHANGE email email VARCHAR(70);

综合:

-- 非空约束
-- 创建表时 添加非空约束
CREATE TABLE test_null (
	id INT NOT NULL, -- 添加非空约束
	last_name VARCHAR(50), -- 添加非空约束
	email VARCHAR(50),
	salary DECIMAL(10,0) -- 一定要指定定点数,不然默认是 10,0
);

-- 向表中添加数据
INSERT INTO test_null(id,last_name,email,salary) 
VALUES (1,'haikang','haikang@qq3434',324324);

-- 报错:Column 'id' cannot be null 不能为null值
-- 就是添加了非空约束此字段不能为null值
INSERT INTO test_null(id,last_name,email,salary) 
VALUES (NULL,'haikang','haikang@qq3434',324324);


-- 查看表结构 
DESC test_null;
-- 创建表后,添加非空约束 两种方式
-- 给字段添加非空约束的前提,该字段不能存在有null值的记录
ALTER TABLE test_null MODIFY  last_name VARCHAR(50) NOT NULL;
ALTER TABLE test_null CHANGE email email VARCHAR(70) NOT NULL;

-- 删除非空约束
ALTER TABLE test_null MODIFY last_name VARCHAR(50);
ALTER TABLE test_null CHANGE email email VARCHAR(70);
 如何查看表中的约束
SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'test1';

CREATE DATABASE dbtest13;
USE dbtest13;
#3. not null (非空约束)
#3.1 在CREATE TABLE时添加约束

CREATE TABLE test1(
id INT NOT NULL,
last_name VARCHAR(15) NOT NULL,
email VARCHAR(25),
salary DECIMAL(10,2)

);

DESC test1;

INSERT INTO test1(id,last_name,email,salary)
VALUES(1,'Tom','tom@126.com',3400);

#错误:Column 'last_name' cannot be null
INSERT INTO test1(id,last_name,email,salary)
VALUES(2,NULL,'tom1@126.com',3400);

#错误:Column 'id' cannot be null
INSERT INTO test1(id,last_name,email,salary)
VALUES(NULL,'Jerry','jerry@126.com',3400);

INSERT INTO test1(id,email)
VALUES(2,'abc@126.com');

UPDATE test1
SET last_name = NULL
WHERE id = 1;

UPDATE test1
SET email = 'tom@126.com'
WHERE id = 1;

#3.2 在ALTER TABLE时添加约束
SELECT * FROM test1;

DESC test1;

ALTER TABLE test1
MODIFY email VARCHAR(25) NOT NULL;

#3.3 在ALTER TABLE时删除约束
ALTER TABLE test1
MODIFY email VARCHAR(25) NULL;
唯一性约束

作用:用来限制某个字段,某列的值不能重复

唯一约束,允许出现多个空值:NULL

关键字:UNIQUE

特点:

  • 同一个表可以有多个唯一约束
  • 唯一约束可以是某一个列的值唯一,也可以多个列组合的值唯一
  • 唯一性约束允许列值为空
  • 在创建唯一约束的时候,如果不给唯一约束命名,就默认和列名相同
  • MYSQL会唯一约束的列上默认创建一个唯一索引
添加唯一约束
1)创建表时添加

create table 表名称(
字段名 数据类型,
字段名 数据类型 unique,
字段名 数据类型 unique key,
字段名 数据类型
);
create table 表名称(
字段名 数据类型,
字段名 数据类型,
字段名 数据类型,
[constraint 约束名] unique key(字段名)
    -- 注意是:如果是组合唯一约束,只能组合中出现了不同就可以添加成功
);

关于复合唯一约束:

create table 表名称(
字段名 数据类型,
字段名 数据类型,
字段名 数据类型,
unique key(字段列表) #字段列表中写的是多个字段名,多个字段名用逗号分隔,表示那么是复合唯一,即多
个字段的组合是唯一的
);

案例

CREATE TABLE时添加约束
CREATE TABLE test2(
id INT UNIQUE, #列级约束
last_name VARCHAR(15) ,
email VARCHAR(25),
salary DECIMAL(10,2),
#表级约束
CONSTRAINT uk_test2_email UNIQUE(email)
);

DESC test2;


SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'test2';

#在创建唯一约束的时候,如果不给唯一约束命名,就默认和列名相同。

INSERT INTO test2(id,last_name,email,salary)
VALUES(1,'Tom','tom@126.com',4500);

#错误:Duplicate entry '1' for key 'test2.id'
INSERT INTO test2(id,last_name,email,salary)
VALUES(1,'Tom1','tom1@126.com',4600);

#错误:Duplicate entry 'tom@126.com' for key 'test2.uk_test2_email'
INSERT INTO test2(id,last_name,email,salary)
VALUES(2,'Tom1','tom@126.com',4600);

#可以向声明为unique的字段上添加null值。而且可以多次添加null
INSERT INTO test2(id,last_name,email,salary)
VALUES(2,'Tom1',NULL,4600);

INSERT INTO test2(id,last_name,email,salary)
VALUES(3,'Tom2',NULL,4600);

SELECT * FROM test2;



#案例:复合的唯一性约束的案例
#学生表
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');#成功

SELECT * FROM student;

SELECT * FROM course;

INSERT INTO student_course VALUES
(1, 1, 1001, 89),
(2, 1, 1002, 90),
(3, 2, 1001, 88),
(4, 2, 1002, 56);#成功

SELECT * FROM student_course;

#错误:Duplicate entry '2-1002' for key 'student_course.sid'
INSERT INTO student_course VALUES
(5,2,1002,67);

密码和用户名是组合的唯一约束,在添加数据时,只要密码和用户名中一个不相同就可以,添加成功

(2)创建表后添加

语法:

两种方式:

方式一:

#字段列表中如果是一个字段,表示该列的值唯一,如果是两种或更多字段,那么复合唯一,即多个字段的组合是唯一的
ALTER TABLE 表名 ADD UNIQUE KEY(字段列表);

方式二:

#方式二:ALTER TABLE 表名 MODIFY 字段名 字段类型 UNIQUE;

案例

ALTER TABLE时添加约束

DESC test2;

UPDATE test2
SET salary = 5000
WHERE id = 3;
#方式1:
ALTER TABLE test2
ADD CONSTRAINT uk_test2_sal UNIQUE(salary);
#方式2:
ALTER TABLE test2
MODIFY last_name VARCHAR(15) UNIQUE;

#4.3 复合的唯一性约束
CREATE TABLE USER(
id INT,
`name` VARCHAR(15),
`password` VARCHAR(25),

#表级约束
CONSTRAINT uk_user_name_pwd UNIQUE(`name`,`password`)
);

INSERT INTO USER
VALUES(1,'Tom','abc');
#可以成功的:
INSERT INTO USER
VALUES(1,'Tom1','abc');

SELECT *
FROM USER;

(3)删除唯一约束

删除唯一约束
  • 添加唯一性约束的列上也会自动创建唯一索引。
  • 删除唯一约束只能通过删除唯一索引的方式删除。
  • 删除时需要指定唯一索引名,唯一索引名就和唯一约束名一样。
  • 如果创建唯一约束时未指定名称,如果是单列,就默认和列名相同;如果是组合列,那么默认和() 中排在第一个的列名相同。也可以自定义唯一性约束名。
SELECT * FROM information_schema.table_constraints WHERE table_name = '表名'; #查看都有哪些约束
ALTER TABLE USERDROP INDEX uk_name_pwd

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-InS3ac6y-1649391420815)(E:\Typora笔记\java笔记\img\image-20220329181020767.png)]

注意是:可以通过SHOW INDEX FROM 表名;查看表的索引

-- 唯一约束
-- 在创建表添加唯一约束 有两种方式 给每个字段添加唯一约束,另一种是给多个字段组合添加一个唯一约束
-- 方式一:给每个字段添加唯一约束
CREATE TABLE test_unique (
	id INT UNIQUE, -- 如果不给唯一约束起名 默认是使用字段名,如果是组合的唯一默认是使用第一字段名
	last_name VARCHAR(25),
	email VARCHAR(50) UNIQUE,
	salary DECIMAL(10,2) -- 一定要指定小数点位数,不然默认是10,0
);

-- 向表中添加数据
INSERT INTO test_unique VALUES(1,'haikang','haikang@123',23423);
-- Duplicate entry '1' for key 'id' 报错因为是 id 是唯一约束
INSERT INTO test_unique VALUES(1,'gbk','gbk@123',23423);

-- 说明唯一约束可以添加多个null
INSERT INTO test_unique VALUES(NULL,'gbk','gbk@123',23423);
INSERT INTO test_unique VALUES(NULL,'gbk','gbk@1235',23423);
-- 查询表结构 
DESC test_unique;
SELECT * FROM test_unique;

-- 方式2 给表中的组合字段添加唯一约束
CREATE TABLE test_unique2(
	id INT,
	last_name VARCHAR(25),
	`password` VARCHAR(50),
	CONSTRAINT t_uni_name_paw UNIQUE KEY(last_name,`password`)
);

-- 向表中添加数据 只能是 last_name 和 password 中有一个字段不相同就可以添加成功
INSERT INTO test_unique2 VALUES(1,'haikang','password');
INSERT INTO test_unique2 VALUES(1,'haikang','password2');-- 添加成功因为是 password2 两者字段有一个存在不同
-- Duplicate entry 'haikang-password' for key 't_uni_name_paw'报错因为是上面已经有该组合字段了
INSERT INTO test_unique2 VALUES(1,'haikang','password');

SELECT * FROM test_unique2;

-- 删除唯一约束 必须使用唯一约束的索引 进行删除
ALTER TABLE test_unique DROP  INDEX id;

-- 删除组合的唯一约束
ALTER TABLE test_unique2 DROP INDEX t_uni_name_paw;
PRIMARY KEY约束【重点】

**作用:**用来唯一标识表中的一行记录

关键字:PRIMARY KEY

特点:

  • 主键约束相当于唯一约束+非空约束的组合,主键约束不允许重复,也不允许出现空值。
  • 一个表最多只能有一个主键约束,建立主键约束可以在列级别创建,也可以在表级别上创建。
  • 主键约束对应着表中的一列或者多列(复合主键)
  • 如果是多列组合的复合主键约束,那么这些列都不允许为空值,并且组合的值不允许重复【就是组合字段中不允许有空值】。
  • MySQL的主键名总是PRIMARY,就算自己命名了主键约束名也没用。
  • 当创建主键约束时,系统默认会在所在的列或列组合上建立对应的主键索引(能够根据主键查询 的,就根据主键查询,效率更高)。如果删除主键约束了,主键约束对应的索引就自动删除了。
  • 需要注意的一点是,不要修改主键字段的值。因为主键是数据记录的唯一标识,如果修改了主键的 值,就有可能会破坏数据的完整性。
添加主键约束

分类:创建表时添加 ALTER TABLE时添加、

语法:

-- 方式一:列级方式
create table 表名称(
字段名 数据类型 primary key, #列级模式
字段名 数据类型,
字段名 数据类型
);

-- 方式二:表级方式
create table 表名称(
字段名 数据类型,
字段名 数据类型,
字段名 数据类型,
[constraint 约束名] primary key(字段名) #表级模式
);

案例:

-- 主键约束
-- 添加主键约束
-- 方式一:创建表时,添加
-- 报错:因为一个表中只能有一个主键约束
-- Multiple primary key defined
CREATE TABLE test_primary(
	id INT PRIMARY KEY,-- 添加主键约束
	last_name VARCHAR(35),
	email VARCHAR(50) PRIMARY KEY,-- 添加主键约束
	salary DECIMAL(10,2)
);


CREATE TABLE test_primary(
	id INT PRIMARY KEY,-- 添加主键约束
	last_name VARCHAR(35),
	email VARCHAR(50),
	salary DECIMAL(10,2)
);

-- 向表中添加数据
INSERT INTO test_primary VALUES (1,'haikang','haikang@433',33483);
-- 报错:因为 主键1的值已经存在 Duplicate entry '1' for key 'PRIMARY'
INSERT INTO test_primary VALUES (1,'haikang','haikang@433',33483);
-- 报错:因为 主键 id 不能为null Column 'id' cannot be null
INSERT INTO test_primary VALUES (NULL,'haikang','haikang@433',33483);

-- 创建表时,添加主键约束是一个组合的
CREATE TABLE test_primary2(
	last_name VARCHAR(35),
	`password` VARCHAR(50),
	email VARCHAR(50),
	salary DECIMAL(10,2),
	PRIMARY KEY(last_name,`password`) -- 给 last_name password 组合添加一个主键约束
);

-- 向表中添加数据时,只能组合字段中有一个不相同,就可以添加成功,并且组合字段中不允许有 null 值
INSERT INTO test_primary2 VALUES('haikang','eeje','haikang@343',89798);
-- 可以添加成功是 组合字段中有一个值不相同
INSERT INTO test_primary2 VALUES('haikang','udeeje','haikang@343',89798);
-- 报错:组合字段中不允许有 null 值 Column 'last_name' cannot be null
INSERT INTO test_primary2 VALUES(NULL,'eeje','haikang@343',89798);

-- 在创建表后 添加主键约束
CREATE TABLE test_primary3(
	id INT,
	last_name VARCHAR(50)
);

-- 添加主键约束
-- 字段列表可以是一个字段,也可以是多个字段,如果是多个字段的话,是复合主
ALTER TABLE test_primary3 ADD PRIMARY KEY(id);
-- 删除主键约束 注意是;删除主键约束 非空约束还在
ALTER TABLE test_primary3 DROP PRIMARY KEY;

(2)创建表后 使用 ALTER TABLE

语法:

ALTER TABLE 表名称 ADD PRIMARY KEY(字段列表); #字段列表可以是一个字段,也可以是多个字段,如果是多
个字段的话,是复合主

(3)删除主键约束,一般不会删除主键约束,删除了主键约束,非空约束还在的

语法:

alter table 表名称 drop primary key;

案例:

 primary key (主键约束)
#5.1 在CREATE TABLE时添加约束

#一个表中最多只能有一个主键约束。

#错误:Multiple primary key defined
CREATE TABLE test3(
id INT PRIMARY KEY, #列级约束
last_name VARCHAR(15) PRIMARY KEY,
salary DECIMAL(10,2),
email VARCHAR(25)
);

# 主键约束特征:非空且唯一,用于唯一的标识表中的一条记录。
CREATE TABLE test4(
id INT PRIMARY KEY, #列级约束
last_name VARCHAR(15),
salary DECIMAL(10,2),
email VARCHAR(25)
);

#MySQL的主键名总是PRIMARY,就算自己命名了主键约束名也没用。
CREATE TABLE test5(
id INT , 
last_name VARCHAR(15),
salary DECIMAL(10,2),
email VARCHAR(25),
#表级约束
CONSTRAINT pk_test5_id PRIMARY KEY(id)  #没有必要起名字。
);

SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'test5';

INSERT INTO test4(id,last_name,salary,email)
VALUES(1,'Tom',4500,'tom@126.com');

#错误:Duplicate entry '1' for key 'test4.PRIMARY'
INSERT INTO test4(id,last_name,salary,email)
VALUES(1,'Tom',4500,'tom@126.com');

#错误:Column 'id' cannot be null
INSERT INTO test4(id,last_name,salary,email)
VALUES(NULL,'Tom',4500,'tom@126.com');

SELECT * FROM test4;


CREATE TABLE user1(
id INT,
NAME VARCHAR(15),
PASSWORD VARCHAR(25),

PRIMARY KEY (NAME,PASSWORD)

);
#如果是多列组合的复合主键约束,那么这些列都不允许为空值,并且组合的值不允许重复。
INSERT INTO user1
VALUES(1,'Tom','abc');

INSERT INTO user1
VALUES(1,'Tom1','abc');
#错误:Column 'name' cannot be null
INSERT INTO user1
VALUES(1,NULL,'abc');

SELECT * FROM user1;

#5.2 在ALTER TABLE时添加约束

CREATE TABLE test6(
id INT ,
last_name VARCHAR(15),
salary DECIMAL(10,2),
email VARCHAR(25)
);

DESC test6;

ALTER TABLE test6
ADD PRIMARY KEY (id);

#5.3 如何删除主键约束 (在实际开发中,不会去删除表中的主键约束!)
ALTER TABLE test6
DROP PRIMARY KEY;
自增列:AUTO_INCREMENT

**作用:**某个字段的值自增

关键字:auto_increment

特点:

(1)一个表最多只能有一个自增长列

(2)当需要产生唯一标识符或顺序值时,可设置自增长

(3)自增长列约束的列必须是键列(主键列,唯一键列)

(4)自增约束的列的数据类型必须是整数类型

(5)如果自增列指定了 0 和 null,会在当前最大值的基础上自增;如果自增列手动指定了具体值,直接 赋值为具体值。

错误演示:

create table employee(
    -- 说明自增列只能使用在 唯一约束或主键约束上
eid int auto_increment,
ename varchar(20)
);
# ERROR 1075 (42000): Incorrect table definition; there can be only one auto column
and 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不是整数类
如何指定自增约束

(1)创建表时

语法:

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(字段名)
);

(2)创建表后

语法:

alter table 表名称 modify 字段名 数据类型 auto_increment;

(3)删除自增约束列

语法:

#alter table 表名称 modify 字段名 数据类型 auto_increment;#给这个字段增加自增约束
alter table 表名称 modify 字段名 数据类型; #去掉auto_increment相当于删除

案例:

-- 自增列 auto_increment
-- 创建表时
CREATE TABLE test_auto_increment(
	id INT PRIMARY KEY AUTO_INCREMENT,
	last_name VARCHAR(30)
);

-- 在添加数据时,可以不用考虑 自增列
INSERT INTO test_auto_increment(last_name) VALUES('haikang'),('明天');

-- 说明在向自增中 指定 0 或 null 时,自增列会自动向上增加
INSERT INTO test_auto_increment VALUES(0,'向明'),(NULL,'海康');

SELECT * FROM test_auto_increment;

-- 在创建表后,添加自增列
CREATE TABLE test_auto_increment2(
	id INT PRIMARY KEY,
	last_name VARCHAR(50)
);
-- 添加自增列
ALTER TABLE test_auto_increment2 MODIFY id INT AUTO_INCREMENT;

-- 删除自增列
ALTER TABLE test_auto_increment2 MODIFY id INT;

案例:必须重点理解下面代码

自增长列:AUTO_INCREMENT
# 6.1 在CREATE TABLE时添加
CREATE TABLE test7(
id INT PRIMARY KEY AUTO_INCREMENT,
last_name VARCHAR(15) 
);
#开发中,一旦主键作用的字段上声明有AUTO_INCREMENT,则我们在添加数据时,就不要给主键
#对应的字段去赋值了。
INSERT INTO test7(last_name)
VALUES('Tom');

SELECT * FROM test7;

#当我们向主键(含AUTO_INCREMENT)的字段上添加0 或 null时,实际上会自动的往上添加指定的字段的数值
INSERT INTO test7(id,last_name)
VALUES(0,'Tom');

INSERT INTO test7(id,last_name)
VALUES(NULL,'Tom');

INSERT INTO test7(id,last_name)
VALUES(10,'Tom');

INSERT INTO test7(id,last_name)
VALUES(-10,'Tom');

#6.2 在ALTER TABLE 时添加
CREATE TABLE test8(
id INT PRIMARY KEY ,
last_name VARCHAR(15) 
);

DESC test8;

ALTER TABLE test8
MODIFY id INT AUTO_INCREMENT;

#6.3 在ALTER TABLE 时删除

ALTER TABLE test8
MODIFY id INT ;

#6.4 MySQL 8.0新特性—自增变量的持久化

#在MySQL 5.7中演示
CREATE TABLE test9(
id INT PRIMARY KEY AUTO_INCREMENT
);

INSERT INTO test9
VALUES(0),(0),(0),(0);

SELECT * FROM test9;

DELETE FROM test9
WHERE id = 4;

INSERT INTO test9
VALUES(0);

DELETE FROM test9
WHERE id = 5;

#重启服务器

SELECT * FROM test9;

INSERT INTO test9
VALUES(0);


#在MySQL 8.0中演示
CREATE TABLE test9(
id INT PRIMARY KEY AUTO_INCREMENT
);

INSERT INTO test9
VALUES(0),(0),(0),(0);

SELECT * FROM test9;

DELETE FROM test9
WHERE id = 4;

INSERT INTO test9
VALUES(0);

DELETE FROM test9
WHERE id = 5;

#重启服务器

SELECT * FROM test9;

INSERT INTO test9
VALUES(0);

#7.foreign key (外键约束)
#7.1 在CREATE TABLE 时添加
MYSQL8.0新特性–自增变量的持久化【重点】

MySQL 8.0之前,自增主键AUTO_INCREMENT的值如果大于max(primary key)+1,在MySQL重启后,会重 置AUTO_INCREMENT=max(primary key)+1,这种现象在某些情况下会导致业务主键冲突或者其他难以发 现的问题。 下面通过案例来对比不同的版本中自增变量是否持久化。 在MySQL 5.7版本中,测试步骤如 下: 创建的数据表中包含自增主键的id字段,语句如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eUuCgSoK-1649391420815)(E:\Typora笔记\java笔记\img\image-20220330105726153.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pQjEvWSu-1649391420816)(E:\Typora笔记\java笔记\img\image-20220330105747841.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JbbJ4fGa-1649391420816)(E:\Typora笔记\java笔记\img\image-20220330105820942.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wysSOavP-1649391420816)(E:\Typora笔记\java笔记\img\image-20220330105842857.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N1hRyE19-1649391420817)(E:\Typora笔记\java笔记\img\image-20220330105916090.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i2KiXr31-1649391420817)(E:\Typora笔记\java笔记\img\image-20220330110126811.png)]

FOREIGN KEY约束

注意是:外键约束只是影响增删改的操作,对查询没有影响

作用:

限定某个表的某个字段引用完整性

比如:员工表的员工所在部门的选择,必须 在部门表能找到对应的部分

关键字:FOREIGN KEY

主表和从表、父表和子表

主表(父表):被引用的表,被参考的表

从表(子表):引用别人的表,参考别人的表

例如:员工表的员工所在部门这个字段的值要参考部门表,部门表是主表,员工表是从表

例如:学生表,课程表,选课表:选课表的学生和课程要分别参考学生表和课程表,学生表和课程表是主表,选课表是从表。

特点

(1)从表的外键列,必须引用/参考主表的主键或唯一约束的列 为什么?因为被依赖/被参考的值必须是唯一的

(2)在创建外键约束时,如果不给外键约束命名,默认名不是列名,而是自动产生一个外键名(例如 student_ibfk_1;),也可以指定外键约束名。

(3)创建(CREATE)表时就指定外键约束的话,先创建主表,再创建从表

(4)删表时,先删从表(或先删除外键约束),再删除主表

(5)当主表的记录被从表参照时,主表的记录将不允许删除,如果要删除数据,需要先删除从表中依赖 该记录的数据,然后才可以删除主表的数据

(6)在“从表”中指定外键约束,并且一个表可以建立多个外键约束

(7)从表的外键列与主表被参照的列名字可以不相同,但是数据类型必须一样,逻辑意义一致。如果类 型不一样,创建子表时,就会出现错误“ERROR 1005 (HY000): Can't create table'database.tablename'(errno: 150)”。 例如:都是表示部门编号,都是int类型。

(8)当创建外键约束时,系统默认会在所在的列上建立对应的普通索引。但是索引名是外键的约束 名。(根据外键查询效率很高)

(9)删除外键约束后,还必须 手动 删除对应的索引

添加外键约束

(1)创建表时

外键约束必须存在于,主表中的主键约束或唯一约束

语法:

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

(2)创建表后,使用ALTER

语法:

ALTER TABLE 从表名 ADD [CONSTRAINT 约束名] FOREIGN KEY (从表的字段) REFERENCES 主表名(被引用
字段) [on update xx][on delete xx];

案例:

ALTER TABLE emp1
ADD [CONSTRAINT emp_dept_id_fk] FOREIGN KEY(dept_id) REFERENCES dept(dept_id);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c9xDxhuG-1649391420817)(E:\Typora笔记\java笔记\img\image-20220330130536314.png)]

(3)删除外键约束

语法:

(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: 0
mysql> show index from emp;

约束等级

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e9Jpiyma-1649391420818)(E:\Typora笔记\java笔记\img\image-20220330130719214.png)]

案例:

主表和从表;父表和子表

#①先创建主表
CREATE TABLE dept1(
dept_id INT,
dept_name VARCHAR(15)
);
#②再创建从表
CREATE TABLE emp1(
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(15),
department_id INT,

#表级约束
CONSTRAINT fk_emp1_dept_id FOREIGN KEY (department_id) REFERENCES dept1(dept_id)

);

#上述操作报错,因为主表中的dept_id上没有主键约束或唯一性约束。
#③ 添加
ALTER TABLE dept1
ADD PRIMARY KEY (dept_id);

DESC dept1;

#④ 再创建从表
CREATE TABLE emp1(
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(15),
department_id INT,

#表级约束
CONSTRAINT fk_emp1_dept_id FOREIGN KEY (department_id) REFERENCES dept1(dept_id)

);

DESC emp1;


SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'emp1';

#7.2 演示外键的效果
#添加失败
INSERT INTO emp1
VALUES(1001,'Tom',10);

#
INSERT INTO dept1
VALUES(10,'IT');
#在主表dept1中添加了10号部门以后,我们就可以在从表中添加10号部门的员工
INSERT INTO emp1
VALUES(1001,'Tom',10);

#删除失败
DELETE FROM dept1
WHERE dept_id = 10;

#更新失败
UPDATE dept1
SET dept_id = 20
WHERE dept_id = 10;

#7.3 在ALTER TABLE时添加外键约束
CREATE TABLE dept2(
dept_id INT PRIMARY KEY,
dept_name VARCHAR(15)
);

CREATE TABLE emp2(
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(15),
department_id INT
);

ALTER TABLE emp2
ADD CONSTRAINT fk_emp2_dept_id FOREIGN KEY(department_id) REFERENCES dept2(dept_id);

SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'emp2';

#7.4 ###  约束等级

-- `Cascade方式`:在父表上update/delete记录时,同步update/delete掉子表的匹配记录 

-- `Set null方式`:在父表上update/delete记录时,将子表上匹配记录的列设为null,但是要注意子表的外键列不能为not null  

-- `No action方式`:如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作  

-- `Restrict方式`:同no action, 都是立即检查外键约束

-- `Set default方式`(在可视化工具SQLyog中可能显示空白):父表有变更时,子表将外键列设置成一个默认的值,但Innodb不能识别

#演示:
# on update cascade on delete set null
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);


UPDATE dept
SET did = 1004
WHERE did = 1002;

DELETE FROM dept
WHERE did = 1004;


SELECT * FROM dept;

SELECT * FROM emp;

#结论:对于外键约束,最好是采用: `ON UPDATE CASCADE ON DELETE RESTRICT` 的方式。


#7.5 删除外键约束

#一个表中可以声明有多个外键约束
USE atguigudb;
SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'employees';

USE dbtest13;

SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'emp1';

#删除外键约束

ALTER TABLE emp1
DROP FOREIGN KEY fk_emp1_dept_id;

#再手动的删除外键约束对应的普通索引
SHOW INDEX FROM emp1;

ALTER TABLE emp1
DROP INDEX fk_emp1_dept_id;
-- 外键约束
-- 创建表时 添加 前提必须先创建主表(父表)
CREATE TABLE dep1(
	did INT,
	dname VARCHAR(25)
);

CREATE TABLE emp1(
	id INT PRIMARY KEY AUTO_INCREMENT,
	ename VARCHAR(30) NOT NULL, -- 非空约束
	department_id INT,
 	-- 外键约束 
	CONSTRAINT fk_emp_dep_id FOREIGN KEY(department_id) REFERENCES dep1(did) -- 报错因为是 dep1 did 不是一个主键约束或唯一约束
);

-- 给dep1 表添加主键约束
ALTER TABLE dep1 ADD  PRIMARY KEY(did);

-- 再次创建

CREATE TABLE emp1(
	id INT PRIMARY KEY AUTO_INCREMENT,
	ename VARCHAR(30) NOT NULL, -- 非空约束
	department_id INT,
 	-- 外键约束 
	CONSTRAINT fk_emp_dep_id FOREIGN KEY(department_id) REFERENCES dep1(did) -- 报错因为是 dep1 did 不是一个主键约束或唯一约束
);

-- 添加数据时,必须是主表有该数据才能添加成功
INSERT INTO dep1 VALUES(1,'教学部'),(2,'教研部');

-- 向emp1表中添加数据
INSERT INTO emp1(ename,department_id) VALUES('湛江',1),('海康',2);

-- 报错:因为dep1表中没有 3 这个 部门所以报错了 Cannot add or update a child row: a foreign key constraint fails
INSERT INTO emp1(ename ,department_id) VALUES('西安',3);

-- 删除关联的外键 数据 也会报错 :Unknown column 'id' in 'where clause'
DELETE FROM  dep1 WHERE id = 2;

-- 更改 关联的外键 数据 也会报错 :Unknown column 'id' in 'where clause'
UPDATE dep1 SET id = 5 WHERE id =2;

-- 创建表后 使用 alter 添加外键约束
CREATE TABLE dep2(
	did INT PRIMARY KEY,
	dname VARCHAR(25)
);
CREATE TABLE emp2(
	id INT PRIMARY KEY AUTO_INCREMENT,
	ename VARCHAR(30) NOT NULL, -- 非空约束
	department_id INT
);

-- 添加外键约束
ALTER TABLE emp2 ADD CONSTRAINT fk_emp2_department_id FOREIGN KEY(department_id) REFERENCES dep2(did);

-- 删除外键约束
ALTER TABLE emp2 DROP FOREIGN KEY fk_emp2_department_id ;
-- 如果还要删除普通索引 
ALTER TABLE emp2 DROP INDEX fk_emp2_department_id;
开发场景【重点】

问题1:如果两个表之间有关系(一对一、一对多),比如:员工表和部门表(一对多),它们之间是否 一定要建外键约束?

答:不是的

问题2:建和不建外键约束有什么区别?

答:建外键约束,你的操作(创建表、删除表、添加、修改、删除)会受到限制,从语法层面受到限 制。例如:在员工表中不可能添加一个员工信息,它的部门的值在部门表中找不到。 不建外键约束,你的操作(创建表、删除表、添加、修改、删除)不受限制,要保证数据的 引用完整 性 ,只能依 靠程序员的自觉 ,或者是 在Java程序中进行限定 。例如:在员工表中,可以添加一个员工的 信息,它的部门指定为一个完全不存在的部门。

问题3:那么建和不建外键约束和查询有没有关系?

答:没有

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tIAX1NNh-1649391420819)(E:\Typora笔记\java笔记\img\image-20220330125944472.png)]

所以说尽量不要使用 外键约束,可能因为外键约束的系统开销而变得非常慢,解决方案是在应用层面使用业务逻辑检验

阿里开发规范

强制】不得使用外键与级联,一切外键概念必须在应用层解决

说明:(概念解释)学生表中的 student_id 是主键,那么成绩表中的 student_id 则为外键。如果更新学 生表中的 student_id,同时触发成绩表中的student_id 更新,即为级联更新。外键与级联更新适用于 单 机低并发 ,不适合 分布式 、 高并发集群 ;级联更新是强阻塞,存在数据库 更新风暴 的风险;外键影响 数据库的 插入速度

CHECK约束

作用:检查某个字段的值是否符号xx要求,一般指的是值的范围

关键字:CHECK

说明:MYSQL5.7不支持

MYSQL5.7可以使用check约束,但check约束对数据验证没有任何作用。添加数据时,没有任何错误或警告。

但是mysql8.0中可以使用check约束了

create table employee(
    eid int primary key,
    ename varchar(5),
    gender char check ('男' or '女')
);

CREATE TABLE temp(
    id INT AUTO_INCREMENT,
    NAME VARCHAR(20),
    age INT CHECK(age > 20),
    PRIMARY KEY(id)
);
DEFAULT约束

**作用:**给某个字段,某列指定默认值,一旦设置默认值,在插入数据时,如果此字段没有显示赋值,则赋值为默认值。

如何给字段加默认值

(1)创建表时

语法:

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(字段名)
);
说明:默认值约束一般不在唯一键和主键列上

案例:

-- default 约束
-- 创建表时,添加default约束
CREATE TABLE test_default(
	id INT PRIMARY KEY AUTO_INCREMENT,
	last_name VARCHAR(20) NOT NULL, -- 非空约束
	gender CHAR(2) DEFAULT '人妖',
	tel CHAR(11) NOT NULL DEFAULT '' #默认空字符串
);

INSERT INTO test_default(last_name,tel) VALUES('吴*凡','fsdf');
SELECT * FROM test_default;

(2)创建表后,使用alter关键字

alter table 表名称 modify 字段名 数据类型 default 默认值;
#如果这个字段原来有非空约束,你还保留非空约束,那么在加默认值约束时,还得保留非空约束,否则非空约束就被
#删除了
#同理,在给某个字段加非空约束也一样,如果这个字段原来有默认值约束,你想保留,也要在modify语句中保留默
认值约束,否则就删除了
alter table 表名称 modify 字段名 数据类型 default 默认值 not null;

注意是:如果给定 的字段原来有非空约束not null,再设置default约束时,原来的not null约束会被覆盖

案例:

-- 在创建表后 添加default约束
CREATE TABLE test_default2(
	id INT PRIMARY KEY AUTO_INCREMENT,
	last_name VARCHAR(20) NOT NULL,
	salary DECIMAL(10,2)
);

-- 添加默认值约束
ALTER TABLE test_default2 MODIFY salary DECIMAL(10,2) DEFAULT 8888 NOT NULL;
-- 添加数据
INSERT INTO test_default2(last_name) VALUES('haikang');
SELECT * FROM test_default2;

(3)删除default约束

alter table 表名称 modify 字段名 数据类型 ;#删除默认值约束,也不保留非空约束alter table 表名称 modify 字段名 数据类型 not null; #删除默认值约束,保留非空约束

案例:

-- 删除default约束ALTER TABLE test_default2 MODIFY salary DECIMAL(10,2);
面试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tmk3X702-1649391420819)(E:\Typora笔记\java笔记\img\image-20220330153539833.png)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值