MySql(18)约束

Mysql专栏入口

链接:https://pan.baidu.com/s/1zAhDUNv-yuJiWmaFLvTk4w
提取码:ttst
提取码:ttst
专栏中有mysql的导入导出,里面有教如何导入

一、约束(constraint)概述

1.1 为什么需要约束

数据完整性(Data Integrity)是指数据的精确性(Accuracy)和可靠性(Reliability)。它是防止数据库中存在不符合语义规定的数据和防止因错误信息的输入输出造成无效操作或错误信息而提出的

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

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

1.2 什么是约束

约束是表级的强制规定。

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

1.3 约束的分类

1.3.1 单列约束 vs 多列约束

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

1.3.2 列约束 vs 表约束

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

1.3.3 以约束的作用分类

  1. NOT NULL 非空约束,规定某个字段不能为空
  2. UNIQUE 唯一约束,规定某个字段在整个表中是唯一的
  3. PRIMARY KEY 主键(非空且唯一)约束
  4. FOREIGN KEY 外键约束
  5. CHECK 检查约束
  6. DEFAULT 默认值约束

1.3基本使用规则

# 查看某个表已有的约束
SELECT * FROM information_schema.table_constraints WHERE table_name = '表名称';

# 创建时添加
CREATE TABLE时添加约束

# 修改
ALTER TABLE 时增加约束、删除约束

二、功能类型约束的使用

2.1 非空约束

NOT NULL


CREATE DATABASE dbtest13

USE dbtest13

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

DESC test1

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

insert into test1 values(1,'张三','zs@126.com','3400'); #成功

insert into test1 values(2,null,'zs@126.com',3400);#名字为空 1048 - Column 'last_name' cannot be null

insert into test1 values(2,'张三',null,'3400');#成功,邮箱允许为空

# 添加约束
ALTER TABLE test1
MODIFY email VARCHAR(25) NOT NULL # 表中已有email为空的值所以不能修改为非空 1138 - Invalid use of NULL value

# 修改表中的email空值
UPDATE test1 SET email = 'zs@126.com' WHERE id = 2

# 添加约束
ALTER TABLE test1
MODIFY email VARCHAR(25) NOT NULL # 成功

# 删除约束
ALTER TABLE test1
MODIFY email VARCHAR(25) NULL # 成功

2.2 唯一约束

UNIQUE

  • 同一个表可以有多个唯一约束。
  • 唯一约束可以是某一个列的值唯一,也可以多个列组合的值唯一。
  • 唯一性约束允许列值为空。
  • 在创建唯一约束的时候,如果不给唯一约束命名,就默认和列名相同。
  • MySQL会给唯一约束的列上默认创建一个唯一索引。
unique  (唯一性约束)
#用来限制某个字段/某列的值不能重复。
在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)#uk_test2_email为email的约束名
);

DESC test2;
/*
+-----------+---------------+------+-----+---------+-------+
| Field     | Type          | Null | Key | Default | Extra |
+-----------+---------------+------+-----+---------+-------+
| id        | int           | YES  | UNI | NULL    |       |
| last_name | varchar(15)   | YES  |     | NULL    |       |
| email     | varchar(25)   | YES  | UNI | NULL    |       |
| salary    | decimal(10,2) | YES  |     | NULL    |       |
+-----------+---------------+------+-----+---------+-------+
*/
SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'test2';
/*
+--------------------+-------------------+-----------------+--------------+------------+-----------------+----------+
| CONSTRAINT_CATALOG | CONSTRAINT_SCHEMA | CONSTRAINT_NAME | TABLE_SCHEMA | TABLE_NAME | CONSTRAINT_TYPE | ENFORCED |
+--------------------+-------------------+-----------------+--------------+------------+-----------------+----------+
| def                | dbtest13          | id              | dbtest13     | test2      | UNIQUE          | YES      |
| def                | dbtest13          | uk_test2_email  | dbtest13     | test2      | UNIQUE          | YES      |
+--------------------+-------------------+-----------------+--------------+------------+-----------------+----------+
*/
#在创建唯一约束的时候,如果不给唯一约束命名,就默认和列名相同。
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;
/*
+------+-----------+-------------+---------+
| id   | last_name | email       | salary  |
+------+-----------+-------------+---------+
|    1 | Tom       | tom@126.com | 4500.00 |
|    2 | Tom1      | NULL        | 4600.00 |
|    3 | Tom2      | NULL        | 4600.00 |
+------+-----------+-------------+---------+
*/
在ALTER TABLE时添加约束
DESC test2;
/*
+-----------+---------------+------+-----+---------+-------+
| Field     | Type          | Null | Key | Default | Extra |
+-----------+---------------+------+-----+---------+-------+
| id        | int           | YES  | UNI | NULL    |       |
| last_name | varchar(15)   | YES  |     | NULL    |       |
| email     | varchar(25)   | YES  | UNI | NULL    |       |
| salary    | decimal(10,2) | YES  |     | NULL    |       |
+-----------+---------------+------+-----+---------+-------+
*/

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;
DESC test2;
/*
+-----------+---------------+------+-----+---------+-------+
| Field     | Type          | Null | Key | Default | Extra |
+-----------+---------------+------+-----+---------+-------+
| id        | int           | YES  | UNI | NULL    |       |
| last_name | varchar(15)   | YES  |     | NULL    |       |
| email     | varchar(25)   | YES  | UNI | NULL    |       |
| salary    | decimal(10,2) | YES  | UNI | NULL    |       |
+-----------+---------------+------+-----+---------+-------+
*/


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

#表级约束
CONSTRAINT uk_user_name_pwd UNIQUE(`name`,`password`)#`name` 和`password`不同时一样即可
);

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

SELECT *
FROM USER;
/*
+------+------+----------+
| id   | name | password |
+------+------+----------+
|    1 | Tom  | abc      |
|    1 | Tom1 | abc      |
+------+------+----------+
*/

#案例:复合的唯一性约束的案例
#学生表
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;
/*
+------+--------+-------------+--------------------+
| sid  | sname  | tel         | cardid             |
+------+--------+-------------+--------------------+
|    1 | 张三   | 13710011002 | 101223199012015623 |
|    2 | 李四   | 13710011003 | 101223199012015624 |
+------+--------+-------------+--------------------+
*/

SELECT * FROM course;
/*
+------+-------+
| cid  | cname |
+------+-------+
| 1001 | Java  |
| 1002 | MySQL |
+------+-------+
*/

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;
/*
+------+------+------+-------+
| id   | sid  | cid  | score |
+------+------+------+-------+
|    1 |    1 | 1001 |    89 |
|    2 |    1 | 1002 |    90 |
|    3 |    2 | 1001 |    88 |
|    4 |    2 | 1002 |    56 |
+------+------+------+-------+
*/

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


删除唯一性约束
-- 添加唯一性约束的列上也会自动创建唯一索引。
-- 删除唯一约束只能通过删除唯一索引的方式删除。
-- 删除时需要指定唯一索引名,唯一索引名就和唯一约束名一样。
-- 如果创建唯一约束时未指定名称,如果是单列,就默认和列名相同;如果是组合列,那么默认和()中排在第一个的列名相同。也可以自定义唯一性约束名。


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

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

DESC test2;
/*
+-----------+---------------+------+-----+---------+-------+
| Field     | Type          | Null | Key | Default | Extra |
+-----------+---------------+------+-----+---------+-------+
| id        | int           | YES  | UNI | NULL    |       |
| last_name | varchar(15)   | YES  |     | NULL    |       |
| email     | varchar(25)   | YES  | UNI | NULL    |       |
| salary    | decimal(10,2) | YES  | UNI | NULL    |       |
+-----------+---------------+------+-----+---------+-------+
*/
#如何删除唯一性索引
ALTER TABLE test2
DROP INDEX last_name;

ALTER TABLE test2
DROP INDEX uk_test2_sal;
/*
+-----------+---------------+------+-----+---------+-------+
| Field     | Type          | Null | Key | Default | Extra |
+-----------+---------------+------+-----+---------+-------+
| id        | int           | YES  | UNI | NULL    |       |
| last_name | varchar(15)   | YES  |     | NULL    |       |
| email     | varchar(25)   | YES  | UNI | NULL    |       |
| salary    | decimal(10,2) | YES  |     | NULL    |       |
+-----------+---------------+------+-----+---------+-------+
*/

2.3 主键(PRIMARY KEY)约束

类似于 唯一约束+非空约束

primary key (主键约束)
#用来唯一标识表中的一行记录。
#主键约束相当于唯一约束+非空约束的组合,主键约束列不允许重复,也不允许出现空值。
在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)  #没有必要起名字(起不起主键的名字都是PRIMARY)
);

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;
/*
+----+-----------+---------+-------------+
| id | last_name | salary  | email       |
+----+-----------+---------+-------------+
|  1 | Tom       | 4500.00 | tom@126.com |
+----+-----------+---------+-------------+
*/


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;
/*
+------+------+----------+
| id   | NAME | PASSWORD |
+------+------+----------+
|    1 | Tom  | abc      |
+------+------+----------+
*/

在ALTER TABLE时添加约束

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

DESC test6;
/*
+-----------+---------------+------+-----+---------+-------+
| Field     | Type          | Null | Key | Default | Extra |
+-----------+---------------+------+-----+---------+-------+
| id        | int           | YES  |     | NULL    |       |
| last_name | varchar(15)   | YES  |     | NULL    |       |
| salary    | decimal(10,2) | YES  |     | NULL    |       |
| email     | varchar(25)   | YES  |     | NULL    |       |
+-----------+---------------+------+-----+---------+-------+
*/
ALTER TABLE test6
ADD PRIMARY KEY (id);
/*
+-----------+---------------+------+-----+---------+-------+
| Field     | Type          | Null | Key | Default | Extra |
+-----------+---------------+------+-----+---------+-------+
| id        | int           | NO   | PRI | NULL    |       |
| last_name | varchar(15)   | YES  |     | NULL    |       |
| salary    | decimal(10,2) | YES  |     | NULL    |       |
| email     | varchar(25)   | YES  |     | NULL    |       |
+-----------+---------------+------+-----+---------+-------+
*/
如何删除主键约束 (在实际开发中,不会去删除表中的主键约束!)
ALTER TABLE test6
DROP PRIMARY KEY;

2.4 AUTO_INCREMENT

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

SELECT * FROM test7;
/*
+----+-----------+
| id | last_name |
+----+-----------+
|  1 | Tom       |
|  2 | Tom       |
+----+-----------+
*/

#当我们向主键(含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');
/*
+-----+-----------+
| id  | last_name |
+-----+-----------+
| -10 | Tom       |
|   1 | Tom       |
|   2 | Tom       |
|   3 | Tom       |
|   4 | Tom       |
|  10 | Tom       |
+-----+-----------+
*/
#开发中,一旦主键作用的字段上声明有AUTO_INCREMENT,则我们在添加数据时,就不要给主键
#对应的字段去赋值了。

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

DESC test8;

ALTER TABLE test8
MODIFY id INT AUTO_INCREMENT;

在ALTER TABLE 时删除

ALTER TABLE test8
MODIFY id INT ;

 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;
/*
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
+----+
*/
DELETE FROM test9
WHERE id = 4;

INSERT INTO test9
VALUES(0);
/*
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  5 |
+----+
*/
DELETE FROM test9
WHERE id = 5;

#重启服务器  net stop mysql57-->net start mysql57

SELECT * FROM test9;
/*
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
+----+
*/
INSERT INTO test9
VALUES(0);
/*
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
+----+
*/
#-->在5.7中,重启后会接着最大的id值后面增加,即id值是放在内存中维护的
#重启后依据现有id的最大值继续增长

#在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);
/*
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  6 |
+----+
*/
#-->MySQL 8.0将自增主键的计数器持久化到 重做日志 中。每次计数器发生改变,都会将其写入重做日志
#中。如果数据库重启,InnoDB会根据重做日志中的信息来初始化计数器的内存值。

2.5 外键(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)删除外键约束后,必须 手动 删除对应的索引

2.6 检查(CHECK)约束

检查某个字段的值是否符合xx要求,一般来说是范围。

CREATE TABLE test10(
id INT,
last_name VARCHAR(15),
salary DECIMAL(10,2) CHECK(salary > 2000)
);

INSERT INTO test10
VALUES(1,'Tom',2500);

#添加失败
INSERT INTO test10
VALUES(2,'Tom1',1500);

SELECT * FROM test10;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值