# 一、约束条件
**约束条件**
|约束条件|说明|
|:---:|:---:|
|`zerofill`|零值填充约束|
|`unsigned`|无符号约束|
|`not null`|非空约束|
|`default`|默认值约束|
|`unique key`|唯一约束 |
|`auto_increment`|自增长约束|
| `primary key` |主键约束|
| `foreign key` |外键约束|
## 1.1 `zerofill`零值填充约束
**当传入字段的数据宽度不够时,使用0进行填充**
```sql
create table zero_fill(id int(3) zerofill);
insert into zero_fill values(1);
select * from zero_fill;
```
![输入图片说明](https://images.gitee.com/uploads/images/2020/1119/233845_f9e60a9a_7841459.png "屏幕截图.png")
## 1.2 `unsigned`无符号约束
**对于数值类型的数据进行的约束**
```sql
create table unsigned_table(id int unsigned);
insert into unsigned_table values(-10),(200); --开启严格模式,插入负数报错
insert into unsigned_table values(0),(200);
```
![输入图片说明](https://images.gitee.com/uploads/images/2020/1119/234302_a19242ba_7841459.png "屏幕截图.png")
## 1.3 `not null`非空约束
**非空约束的字段,在插入值时必须进行插入; 如果不插入则报错**
```sql
create table not_null(id int, name varchar(20) not null);
insert into not_null values (1, "小兰");
insert into not_null(id) values (2); -- 非空字段未插入值,报错
```
![输入图片说明](https://images.gitee.com/uploads/images/2020/1119/234644_6c0cf0a8_7841459.png "屏幕截图.png")
## 1.4 `default value`默认约束
**插入值时,如果没有指定值;则自动填充默认值**
```sql
create table default_value(id int, gender enum("male", "female", "other") default "male");
insert into default_value(id) values(1); -- 非默认值,要指定字段插入
insert into default_value values(2, "female");
```
![输入图片说明](https://images.gitee.com/uploads/images/2020/1119/235145_fcfd9591_7841459.png "屏幕截图.png")
## 1.5 `unique key`唯一约束
**有些字段中的值必须唯一的,使用此约束条件**
* **单列唯一**
```sql
create table unique_key(id int unique key, name char(4));
insert into unique_key values(1, "小明"), (1, "小芳"); -- 报错
insert into unique_key values(1, "小明"), (2, "小芳");
```
![输入图片说明](https://images.gitee.com/uploads/images/2020/1120/000156_97de721e_7841459.png "屏幕截图.png")
* **联合唯一**
> 对于单个字段可以重复,联合起来不能重复,
```sql
create table unique_key2(
id int,
ip varchar(30),
port int,
unique key(ip, port) -- 设置联合唯一
);
insert into unique_key2 values(1, "127.0.0.1", 8080); -- 成功
insert into unique_key2 values(2, "127.0.0.1", 8081); -- 成功
insert into unique_key2 values(2, "127.0.0.1", 8080); -- 失败
```
![输入图片说明](https://images.gitee.com/uploads/images/2020/1120/000756_ffe4f72a_7841459.png "屏幕截图.png")
## 1.6 `primary key`主键约束
> 1. **非空且唯一**
> 2. `Innodb`存储引擎,在创建表时必须使用`primary key`。
> * 一张表中有且只有一个主键
> * 如果没有出现主键约束,则 **第一次出现not null unique key** 约束的做为主键
> * 如果没有设置主键,也没有设置`not null unique key`, `Innodb`会采用内部的隐藏字段做为主键. 这个字段不能使用
> 3. **通常将`id`字段做为表的主键**
```sql
create table primary_key1(id int primary key);
create table primary_key2(
id int not null unique key,
addr char(32) not null unique key
);
create table primary_key3(
id int,
name char(16),
primary key(id, name)
);
```
![输入图片说明](https://images.gitee.com/uploads/images/2020/1120/144527_1bfdf746_7841459.png "屏幕截图.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/1120/144835_aa056826_7841459.png "屏幕截图.png")
## 1.7 `auto_increment` 自增长约束
> 一张表中只有 **一个** 字段自增长。 **非空且唯一** 的字段才可以添加自增长约束
>
> **通常是给主键添加约束的**
>
> 数据删除后,不会清空计数器, 也即是: 自增长继续
>
> **truncate tb_name;** 清空tb_name中的数据,并重置计数器
```sql
create table auto_increment_table(
id int primary key auto_increment,
name char(5)
);
insert into auto_increment_table(name) values("小明"),("小芳");
```
![输入图片说明](https://images.gitee.com/uploads/images/2020/1120/145544_ae0eed70_7841459.png "屏幕截图.png")
# 二、表关系
设计数据库时,我们要尽量将不同的信息存放在不同的表之中。
> 1. 解耦合,对于数据的扩展性好。
> 2. 提高了数据的查询和修改效率,降低存储空间。
如果在设计数据库时,将所有数据存放到一个表之中的后果
> 1. 浪费存储空间, 对于不同的记录之间的数据项可能存在相同的数据
> 2. 修改某个字段的效率低, 如果修改的字段存在多个相同的值,那么修改数据时,这些相同的值都会发送改变,增加了数据库服务的压力(**后果非常严重**)
## 2.1 `foreign key`外键约束
> 1. 用于约束字段只能填充某张表中 **已经存在** 的值
> 2. 用于实现表之间的关系
## 2.2 表关系
创建表时,需要考虑表关系;需要双向考虑。
### 2.2.1 一对多
对于 **学生和学院的关系** , **学生只能在一个学院** ,但是 **学院可以有多个学生, _也即是: 多个学生对应一个学院_ **, (学生和学院之间的关系位 **单向一对多关系** , 也即是 **一对多关系** )。
```sql
-- 创建学院表
create table academy(
academy_id int primary key auto_increment,
academy_name varchar(20)
);
-- 创建学生表
create table student(
student_id int primary key auto_increment,
student_name varchar(20),
student_gender int,
ac_id int,
foreign key(ac_id) references academy(academy_id) -- 当前表字段ac_id与 表academy表(academy_id)关联
on update cascade -- 同步更新
on delete cascade -- 同步删除
);
insert into academy(academy_name) values("计算机"),("理学院"),("人文");
insert into student(student_name, student_gender, ac_id) values("小明", 1, 1),("小芳", 2, 3), ("小兰", 2, 3), ("小蓝", 1, 2);
```
> 1. 创建外键约束时,**在多的一方创建外键约束**
> 2. 创建表时,**先创建被关联表**
> 3. 录入数据时,**先录入被关联表**
> 4. **外键约束语法**: **`foreign key(字段) references 表名(字段)`**。
> 5. 被关联表(`academy`)中没有的数据,不能在关联表(`student`)中插入。
> 6. 如果被关联表(`academy`)中的数据被插入到了关联表(`student`),则被关联表(`academy`)中的被关联字段(`academy_id`)的数据不能修改, 也不能删除此条记录。
> 7. 如果要修改被关联表(`academy`)中的被关联字段(`academy_id`)的数据,则应当对关联表(`student`)中的关联字段(`ac_id`)一起修改。
> 8. 如果要删除被关联表(`academy`)中的被关联字段(`academy_id`)的数据,则应当对关联表(`student`)中的关联字段(`ac_id`)一起删除。
> 9. 级联更新,级联删除。**`foreign key(字段) references 表名(字段) on update cascade on delete cascade`**
![输入图片说明](https://images.gitee.com/uploads/images/2020/1120/160511_54db8bcf_7841459.png "屏幕截图.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/1120/160536_7032653d_7841459.png "屏幕截图.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/1120/160731_0f373d2a_7841459.png "屏幕截图.png")
![输入图片说明](https://images.gitee.com/uploads/images/2020/1120/160831_95aacc3c_7841459.png "屏幕截图.png")
### 2.2.2 多对多
对于作者和作品的关系;一部作品可以有多个作者编写,一名作者也可以编写多本书。(作者和作品 之间存在 **双向的一对多关** 系,也即是: **多对多关系**)
```sql
-- 创建作者表
create table author(
id int primary key auto_increment,
name varchar(10),
age int,
book_id int,
foreign key(boo_id) references book(id)
on update cascade -- 同步更新
on delete cascade -- 同步删除
);
-- 创建book表
create table book(
id int primary key auto_increment,
book_name varchar(20),
price float,
author_id int,
foreign key(author_id) references author(id)
on update cascade -- 同步更新
on delete cascade -- 同步删除
);
```
> 如果这样创建表存在如下问题
> 1. 创建表`author`时,需要关联`book`表,此时`author`表无法创建。
> 2. 创建表`book`时,需要关联`author`表,此时`book`表无法创建。
>
因此创建多多关系表时,需要两外创建一张关系表,用于存放两张表的关系
```sql
create table author(
id int primary key auto_increment,
name varchar(10),
age int
);
-- 创建book表
create table book(
id int primary key auto_increment,
book_name varchar(20),
price float
);
--- 创建book和author关系表
create table book2author(
id int primary key auto_increment,
book_id int,
author_id int,
foreign key(book_id) references book(id)
on update cascade -- 同步更新
on delete cascade, -- 同步删除
foreign key(author_id) references author(id)
on update cascade -- 同步更新
on delete cascade -- 同步删除
);
```
> 1. 数据表之间不存在关系
> 2. 它们之间的关系由第三张表体现
> 3. 操作数据,受到影响的只是对三张表(关系表)
### 2.2.3 一对一
对于一张有很多字段的表,通常都会将表拆分为多个表.
> **好处**
> 1. 查询时,不用一次性的查询出全部的信息;节省数据传输时间
> 2. 可以更好的包含用户的数据安全
对于用户表,会有各种各样的字段信息。通常将表拆分两个表,一张表存放用户的基本信息,另一张表存放用户的详细信息.
```sql
-- 创建用户详情表
create table user_details(
id int primary key auto_increment,
age int,
gender enum("male, female")
);
-- 创建用户表
create table user(
id int primary key auto_increment,
name varchar(20),
user_detail_id int unique,
foreign key(user_detail_id) references user_details(id)
on update cascade -- 同步更新
on delete cascade -- 同步删除
);
```
> 1. 一对一关系的表的外键字段,通常建立在**查询频率最高的表中**
> 2. 一对一关系的表的关键字段通常需要给 **唯一约束** .
# 三、表结构修改
1. 修改表名
```sql
alter table old_tb_name rename to new_tb_name;
```
2. 添加字段
```sql
alter table tb_name add 字段名 字段类型(宽度) 约束条件;
alter table tb_name add 字段名 字段类型(宽度) 约束条件 first;
alter table tb_name add 字段名 字段类型(宽度) 约束条件 after 字符名;
```
3. 删除字段
```sql
alter table tb_name drop 字段名
```
4. 修改字段
```sql
alter table tb_name modify 字段名 字段类型(宽度) 约束条件;
alter table tb_name change 旧字段名 新字段名 新字段类型(宽度) 约束条件;
```
# 四、复制表
`sql`语句查询的结果也是一张表, 从旧表复制数据给新表
```sql
create table new_table_name select * from old_table_name;
```
> 1. 不能复制主键,外键,索引
> 2. 只能复制表结构和数据
```sql
create table new_table_name select * from od_table_name where ...;
```
> 如果后面的条件没有对应数据,也会创建表出来
一键复制
编辑
Web IDE
原始数据
按行查看
历史