数据库中主要有六种约束
指示某列不能存储 NULL 值。
例如在这里对birth添加非空约束
create table student(
id int,
age int,
name varchar(8),
birth date NOT NULL,
math decimal(10, 2),
english decimal(10, 2)
);
接着向其中插入数据,如果不给birth一个确定的值,就会导致插入失败
INSERT INTO student VALUES(6, 13, "马六", NULL, 85.9, 95.4);
ERROR 1048 (23000): Column 'birth' cannot be null
INSERT INTO student(id, age, name) values(3, 16, "李华");
ERROR 1364 (HY000): Field 'birth' doesn't have a default value
添加了非空约束后该列就不能为空,必须要给一个值
保证某列的每行必须有唯一的值,即对于添加了唯一约束的数据项不能有重复
//对id添加unique约束
create table student(
id int UNIQUE,
age int,
name varchar(8),
birth date,
math decimal(10, 2),
english decimal(10, 2)
);
//插入第一条数据
INSERT INTO student VALUES(1, 11, "李华", 20200812, 76.5, 87.5);
Query OK, 1 row affected (0.002 sec)//插入成功
//插入第二条数据,除了id与第一条相同,其他全都不同
INSERT INTO student VALUES(1, 15, "李梅", 20200813, 88.5, 90.5);
ERROR 1062 (23000): Duplicate entry '1' for key 'id'//报错,id必须唯一,不能重复
规定没有给列赋值时的默认值。
//为math和english添加缺省约束,缺省值为60
create table student(
id int,
age int,
name varchar(8),
birth date,
math decimal(10, 2) DEFAULT 60,
english decimal(10, 2) DEFAULT 60
);
//插入数据,没有指定math和english
INTO student(id, age, name) values(3, 16, "李华");
Query OK, 1 row affected (0.001 sec)
select * from student;
+------+------+--------+-------+-------+---------+
| id | age | name | birth | math | english |
+------+------+--------+-------+-------+---------+
| 3 | 16 | 李华 | NULL | 60.00 | 60.00 |
+------+------+--------+-------+-------+---------+
//没有指定时会被修改为默认值
NOT NULL 和 UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录。
主键的特性即非空且唯一,如果在没有指定主键的时候,如果某一列具有非空且唯一的特性,他就会被暂定为主键,但是主键只能有一个。
//id为非空且唯一
create table student(
id int NOT NULL UNIQUE,
age int,
name varchar(8),
birth date,
math decimal(10, 2),
english decimal(10, 2)
);
desc student;//可以看到id成为了主键
+---------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| age | int(11) | YES | | NULL | |
| name | varchar(8) | YES | | NULL | |
| birth | date | YES | | NULL | |
| math | decimal(10,2) | YES | | NULL | |
| english | decimal(10,2) | YES | | NULL | |
+---------+---------------+------+-----+---------+-------+
//使用PRIMARY KEY
DROP TABLE student;
create table student(
id int PRIMARY KEY,
age int,
name varchar(8),
birth date,
math decimal(10, 2),
english decimal(10, 2)
);
DESC student;
+---------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| age | int(11) | YES | | NULL | |
| name | varchar(8) | YES | | NULL | |
| birth | date | YES | | NULL | |
| math | decimal(10,2) | YES | | NULL | |
| english | decimal(10,2) | YES | | NULL | |
+---------+---------------+------+-----+---------+-------+
但是非空且唯一并不代表主键,主键只能有一个,而非空不唯一可以有多个,如果有多个非空不唯一,则只会有第一个是主键
//将id和name都设置为非空且唯一
DROP TABLE student;
create table student(
id int NOT NULL UNIQUE,
age int,
name varchar(8) NOT NULL UNIQUE,
birth date,
math decimal(10, 2),
english decimal(10, 2)
);
desc student;//id和name都是非空且唯一,但是只有id是主键
+---------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| age | int(11) | YES | | NULL | |
| name | varchar(8) | NO | UNI | NULL | |
| birth | date | YES | | NULL | |
| math | decimal(10,2) | YES | | NULL | |
| english | decimal(10,2) | YES | | NULL | |
+---------+---------------+------+-----+---------+-------+
如果想要使用多个列共同作为主键,就得使用下面这种语法
//在末尾表明组合主键的列有哪些
create table student(
id int,
age int,
name varchar(8),
birth date,
math decimal(10, 2),
english decimal(10, 2),
PRIMARY KEY(id, name)
);
+---------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| age | int(11) | YES | | NULL | |
| name | varchar(8) | NO | PRI | NULL | |
| birth | date | YES | | NULL | |
| math | decimal(10,2) | YES | | NULL | |
| english | decimal(10,2) | YES | | NULL | |
+---------+---------------+------+-----+---------+-------+
//不能直接在多个列后面加上PRIMARY KEY,那样的意思是创建多个主键,但是主键是唯一的,所以会报错
//错误写法
create table student(
id int PRIMARY KEY,
age int,
name varchar(8) PRIMARY KEY,
birth date,
math decimal(10, 2),
english decimal(10, 2)
);
ERROR 1068 (42000): Multiple primary key defined//报错,定义了多个主键
添加自增属性的项必须为数字,并且必须为主键,并且只有缺省的时候才会使用自增。
create table student(
id int PRIMARY KEY AUTO_INCREMENT,
age int,
name varchar(8),
birth date,
math decimal(10, 2),
english decimal(10, 2)
);
INSERT INTO student(age, name) values(14, "张三");
INSERT INTO student(age, name) values(16, "李四");
select * from student;
+----+------+--------+-------+------+---------+
| id | age | name | birth | math | english |
+----+------+--------+-------+------+---------+
| 1 | 14 | 张三 | NULL | NULL | NULL |
| 2 | 16 | 李四 | NULL | NULL | NULL |
+----+------+--------+-------+------+---------+
//接着删除前两条
DELETE FROM student WHERE id < 3;
INSERT INTO student(age, name) values(14, "张三");
INSERT INTO student(age, name) values(16, "李四");
INSERT INTO student(age, name) values(19, "王五");
INSERT INTO student(age, name) values(15, "马六");
+----+------+--------+-------+------+---------+
| id | age | name | birth | math | english |
+----+------+--------+-------+------+---------+
| 3 | 14 | 张三 | NULL | NULL | NULL |
| 4 | 16 | 李四 | NULL | NULL | NULL |
| 5 | 19 | 王五 | NULL | NULL | NULL |
| 6 | 15 | 马六 | NULL | NULL | NULL |
+----+------+--------+-------+------+---------+
//可以看到序号并没有被重置,而是从删除的地方继续自增
保证一个表中的数据匹配另一个表中的值的参照完整性。
当我们的表中有数据与另一个表有关联的时候,就需要用到外键约束。例如学生表中存储了班级的信息,但是在班级表中并没有这个班级存在,就会导致数据出现冲突,所以必须将两个表关联起来。
语法
FOREIGN KEY (外键项) REFERENCES 关联表名(关联表中的对应项)
create table classes(
id int PRIMARY KEY AUTO_INCREMENT
);
create table student(
id int PRIMARY KEY AUTO_INCREMENT,
age int,
name varchar(8),
classid int,
FOREIGN KEY (classid) REFERENCES classes(id)
);
//添加班级
insert into classes values(1);
insert into classes values(2);
//插入学生信息
//插入成功
INSERT INTO student(name, classid) VALUES("张三", 1);
INSERT INTO student(name, classid) VALUES("李四", 2);
//插入失败,3号班级并不存在
INSERT INTO student(name, classid) VALUES("王五", 3);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`lee`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`classid`) REFERENCES `classes` (`id`))
保证列中的值符合指定的条件。对于MySQL数据库,对CHECK子句进行分析,但是忽略CHECK子句。
create table student(
id int ,
age int,
name varchar(8),
birth date,
math decimal(10, 2),
english decimal(10, 2),
CHECK(age < 18)//确保年龄小于18
);
//插入一个年龄为11的数据
INSERT INTO student VALUES(1, 11, "李华", 20200812, 76.5, 87.5);
Query OK, 0 rows affected (0.009 sec)//插入成功
在MySQL中,CHECK子句的功能并没有被实现,所以它虽然会对语句进行分析,但是并不会去真正使用这个功能。
如果要设计一个表,首先就要考虑多个表之间的关系
例如学生和班级的关系,一个班级拥有多个学生,但是一个学生只能属于一个班级
例如学生、课程、选课表的关系。
一个学生可以选择多门课程,一个课程也可以被多个学生选择
表的关系只是设计的最基础的一项,考虑好关系,确认好数据项,将数据填进去即可。
但是那样的设计并不合理,可能会存在数据冗余、传输性能、查询性能等问题,所以需要用到三大范式来规范数据库表的设计,减少数据库的冗余性。
范式是针对数据库表设计的几种方案,目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。
通常我们使用的都是第一范式(1NF)、第二范式(2NF)、第三范式(3NF),所以又将他们称为三大范式。
第一范式:要求数据库表的每一列都是不可分割的原子数据项。
例如
在这个表中,家庭信息和学校信息并不是原子的,例如家庭信息中包含了家庭组成和所在地,学校信息包含了年级和学位。
对于第一范式,需要确保每一项数据都是不可分割的原子性数据,不能是一个集合
调整后
第二范式:在第一范式的基础上,非主键数据必须完全依赖主键,不能部分依赖(针对组合主键)
第二范式的目的是确保一个表只说明一个事物
例如
在这个图中订单号和产品号作为组合主键,但是后面的订单信息、订单时间只与订单号相关,而与产品号无关,部分依赖于主键,违反了第二范式。可以看到,后面的数据中存在着大量的重复,造成了数据冗余
第三范式:在第二范式的基础上,非主键数据之间不能相互依赖,依赖关系不能传递,每一个非主键数据都必须要和主键直接依赖而非间接依赖
第三范式主要解决依赖关系传递带来的数据冗余问题
例如
该图中,班主任性别与班主任年龄直接依赖于班主任姓名,而与主键学号并没有直接的依赖关系,而是间接,存在着依赖传递的问题。