目录
2.1.3 第三范式(确保每列都和主键列直接相关,而不是间接相关)
1. 数据库约束
1.1 什么是表约束
表约束是在创建表的时候,设计⼀些表的约束条件,⽤来保证数据的合法性和数据的正确性。
例如⼀个账号只能绑定⼀个⼿机号,那么⼿机号就不能重复,不能被多个账号绑定使⽤,所以它应该设置唯⼀约束。⽽主键是⽤来标识数据的,因此它不能为 NULL,也不能为空,所以他需要设置⾮空约束或(主键约束,主键约束也不能为 NULL)。
1.2 为什么需要表约束
就像法律是⽤来规范⼈们的正确⾏为的⼀样,表约束也是为了规范程序员正确使⽤表的,但表约束是预先设置的,设置之后就对所有插⼊和修改⽴即⽣效,⽐如⾮空约束设置好之后,如果添加和修改为NULL 值就会报错,这点是和法律有细微的不同。如果没有表约束,会导致数据不正确,从⽽导致程序或现实中的业务⽆法推进和执⾏。
1.3 常见约束
常⻅的表约束如下表:
约束 | 说明 |
NOT NULL | ⾮空约束,指示某列不能存储 NULL 值 |
UNIQUE | 唯⼀约束,保证某列的每⾏必须有唯⼀的值 |
PRIMARY KEY | 主键约束,确保某列(或两个列多个列的结合)有唯⼀标识,有助于 更容易更快速地找到表中的⼀个特定的记录。 |
FOREIGN KEY | 外键约束,保证⼀个表中的数据匹配另⼀个表中的值的参照完整性。 |
CHECK | 检查约束, 保证列中的值符合指定的条件。对于MySQL数据库,对 CHECK⼦句进⾏分析,但是忽略CHECK⼦句。 |
AUTO_INCREMENT | ⾃增约束,插⼊可忽略此字段,此字段会⾃⼰增加存储数值。默认是从 1 开始,每次递增 1。 |
DEFAULT | 默认值约束, 规定没有给列赋值时的默认值。 |
1.3.1 非空约束 not null
语法:
create table table_name(字段名 数据类型 not null [,...]);
例如,给id和name加上非空约束 :
插入null值,会报错:
查看非空约束:
使用desc table_name 来查询,NO表示添加了非空约束,YES表示未添加非空约束。
1.3.2 唯一约束 unique
语法:
create table table_name (字段名 数据类型 unique [,...]);
例如,给id加上唯一约束:
添加两条id相同的数据:
此时就会发生错误,无法添加。
注意:
- 一张表中可以有一个或多个唯一约束;
- 唯一约束字段可以插入NULL值;
- 唯一约束字段的NULL可以插入多个.
查看一张表的唯一约束:
1.3.3 主键约束 primary key
主键是可以⽤来表示⼀张表中某条数据的代表凭证,例如对于“⼈”这张表来说,唯⼀的身份证就可以作为主键来代表这个⼈,“姓名”不⾏,因为姓名有可能会重复。
主键的特征:
- 主键可以由多个字段或单个字段组成。
- 主键不能为空且且唯⼀。
- ⼀个表中只能有⼀个主键。
语法1:独立主键
create table table_name (字段名 数据类型 primary key [,...]);
示例:
语法2:联合主键
create table table_name (
字段1 数据类型,
字段2 数据类型
[,...],
primary key(字段1,字段2[,...])
);
示例:
主键约束 VS 唯⼀约束:
- 主键约束⼀个表只能有⼀个,⽽唯⼀约束可以有多个;
- 主键约束不能有 null 值,⽽唯⼀约束可以有 null(唯⼀索引可以有多个 null)。
1.3.4 外键约束 foreign key
外键⽤于关联其他表的主键或唯⼀键,语法:
foreign key (字段名) references 主表(列)
示例:创建班级表classes,id为主键:
创建班级表,有使用MySQL关键字作为字段时,需要使用``来标识
创建学生表student,一个学生对应一个班级,一个班级对应多个学生。使用id为主键,classes_id为外键,关联班级表id
1.3.5 检查约束 check(了解)
语法:
check (<检查约束>)
示例:
特殊说明:检查约束在MySQL 8.0.16才可以使用,在MySQL 8.0.15以前不能使用。
1.3.6 自增约束 auto_increment
语法:
create table table_name(
id int primary key auto_increment,
name varchar(250)
);
示例:
插入两个name:
使用 show create table 表名 可以查看当前的自增值:
当给自增列插入null时,他的执行逻辑和不设置是一样的:
自增也可以手动指定值:
⾃增值可以在创建表的时候⼿动指定:
修改自增值:
使⽤ alter table table_name auto_increment=n,可修改⾃增值为n
注意:
- 一个表中只能有一个自增列;
- ⾃增列的字段类型只能为整数类型(TINYINT、SMALLINT、INT、BIGINT 等);
- auto_increment 必须配合 key ⼀起使⽤,这个 key 可以是 primary key,foreign key,如果没有 key就会报错;
- 唯⼀列可以为⾃增列:
- auto_increment 的值只能设置⽐⽬前存储的最⼤值⼤,否则设置不会⽣效。
delete 和 truncate 重置自增验证:
delete删除不会重置自增值:
truncate删除会重置自增值:
1.3.7 默认约束 default
默认约束是给没有给列赋值时的默认值,语法如下:
字段 数据类型 default 默认值
示例:
1.3.8 insert ... select
2.表设计
2.1 数据库设计三范式
2.1.1 第⼀范式(确保每列保持原子性)
第⼀范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原⼦值,就说明该数据库表满⾜了第⼀范式。第⼀范式的合理遵循需要根据系统的实际需求来定。⽐如某些数据库系统中需要⽤到“地址”这个属性,本来直接将“地址”属性设计成⼀个数据库表的字段就⾏。但是如果系统经常会访问“地址”属性中的“城市”部分,那么就⾮要将“地址”这个属性重新拆分为省份、城市、详细地址等多个部分进⾏存储,这样在对地址中某⼀部分操作的时候将⾮常⽅便。这样设计才算满⾜了数据库的第⼀范式,如下表所示。
上表所示的⽤户信息遵循了第⼀范式的要求,这样在对⽤户使⽤城市进⾏分类的时候就⾮常⽅便,也提⾼了数据库的性能。
2.1.2 第⼆范式(确保表中的每列都和主键相关)
第⼆范式在第⼀范式的基础之上更进⼀层。第⼆范式需要确保数据库表中的每⼀列都和主键相关,⽽不能只与主键的某⼀部分相关(主要针对联合主键⽽⾔)。也就是说在⼀个数据库表中,⼀个表中只能保存⼀种数据,不可以把多种数据保存在同⼀张数据库表中。
⽐如要设计⼀个订单信息表,因为订单中可能会有多种商品,所以要将订单编号和商品编号作为数据库表的联合主键,如下表所示。
这样就产⽣⼀个问题:这个表中是以订单编号和商品编号作为联合主键。这样在该表中商品名称、单位、商品价格等信息不与该表的主键相关,⽽仅仅是与商品编号相关。所以在这⾥违反了第⼆范式的设计原则。⽽如果把这个订单信息表进⾏拆分,把商品信息分离到另⼀个表中,把订单数量表也分离到另⼀个表中,就⾮常完美了。如下所示。
这样设计,在很⼤程度上减⼩了数据库的冗余。如果要获取订单的商品信息,使⽤商品编号到商品信息表中查询即可。
2.1.3 第三范式(确保每列都和主键列直接相关,而不是间接相关)
第三范式需要确保数据表中的每⼀列数据都和主键直接相关,⽽不能间接相关。⽐如在设计⼀个订单数据表的时候,可以将客户编号作为⼀个外键和订单表建⽴相应的关系。⽽不可以在订单表中添加关于客户其它信息(⽐如姓名、所属公司等)的字段。
如下⾯这两个表所示的设计就是⼀个满⾜第三范式的数据库表。不符合第三范式:
正确的表结构:
这样在查询订单信息的时候,就可以使⽤客户编号来引⽤客户信息表中的记录,也不必在订单信息表中多次输⼊客户信息的内容,减⼩了数据冗余。
2.2 表关系
表和表之间的关系有三种:
- ⼀对⼀:⼀个学⽣对应⼀个学号;
- ⼀对多:⼀个班级包含多个学⽣(⽤两张表表示);
- 多对多:⼀张表中的⼀条数据可以对应到另⼀张表的多条数据,反之也是这样的,这样的关系叫做多对多,⼀般⽤三个表表示。
一对一:
一对多:
多对多: