MySQL 库表与约束
MySQL库表与约束
- 一、基础命令操作
- 1.1 登录进入 MySQL
- 1.2 SQL语句概述
- 1.3 MySQL字符集
- 1.3.1 字符集
- 1.3.2 字符序
- 二、数据库操作
- 2.1 数据库常用操作命令
- 2.2 创建库 (create database 数据库名)
- 2.3 查看库 (show databases)
- 2.4 删除库 (drop database 数据库名)
- 2.5 切换库(use 数据库名)
- 2.6 数据库对象
- 2.7 数据库字典
- 三、表的基本操作
- 3.1 数据类型
- 3.2 创建表 (create table 表名 (表选项))
- 3.3 查看表(show/desc)
- 3.4 删除表(drop table [if exists] 表名;)
- 3.5 修改表
- 3.5.1 修改表名(alter/rename;)
- 3.5.2 添加新列(alter talble 表名 add 新列名 列类型;)
- 3.5.3 删除列(alter table 表名 drop 列名;)
- 3.5.4 修改列名(alter table 表名 change 旧列名 新列名 列类型;)
- 3.5.5 修改列类型(alter table 表名 modify 列名 列类型;)
- 3.5.6 修改列位置(alter table 表名 modify 列名 列类型 after 某列;)
- 3.6 复制表的结构(create/insert into)
- 四、表的约束
- 4.1 概念与语法
- 4.2 非空约束 not null
- 4.3 默认值约束 default' '
- 4.4 列描述 comment ' '
- 4.5 主键约束 primary key
- 4.5.1 复合主键 primary key (字段1,字段2)
- 4.5.2 主键自增长 auto_increment
- 4.6 外键约束 foreign key references
- 4.7 唯一性约束 unique
- 4.8 检查约束 check
- 4.9 删除约束
- 五、MySQL库表设计(范式)
- 5.1 范式概念与三范式小结
- 5.2 第一范式(1NF)
- 5.3 第二范式(2NF)
- 5.4 第三范式(3NF)
- 5.5 巴斯-科德范式(BCNF)
- 5.6 第四范式(4NF)- 消除表中的多值依赖关系
- 5.7 第五范式(5NF)/完美范式
- 5.9 第六范式(6NF)/域键范式
- 5.9 反范式 - 不遵循数据库范式设计
- 六、MySQL数据库账户及授权
- 6.1 密码策略
- 6.2 登录账户管理
- 6.3 新建登录账户(create user ''@'' identified by '')
- 6.4 账户授权(grant)
- 6.5 回收权限(revoke)
- 6.6 删除账户(drop user ''@'')
- 练习
一、基础命令操作
1.1 登录进入 MySQL
- 登录MySQL:
# 以root用户登录,-p代表输入密码
mysql -u root -p
# 安全起见,一般情况不会直接在-p后面直接输入密码
mysql -u 用户名 -h 服务器的主机地址 -p密码 -A
#带有密码登录,会有警告,提示不安全
- -u 后面跟登录数据库的用户名,这里使用 root
- -h 后面的参数是服务器的主机地址,如果客户端和服务器在同一台机器上,则输入 localhost 或者 IP 地址
- -p 后面是用户登录密码,注意:
-p 和密码之间没有空格。如果出现空格,系统将不会把后面的字符串当成密码来对待,没有密码时不写 - -A参数:不预读数据库信息,加上该参数则不预读数据库中的表等信息,不会有表名及列名的补全,但读取速度会加快
1.2 SQL语句概述
SQL:结构化查询语言(Structured Query Language),在关系型数据库上执行数据操作、数据检索以及数据维护的标准语言。
在数据库系统中,SQL语句不区分大小写(建议用大写) ,但字符串常量区分大小写
MySQL致力于支持全套ANSI/ISO SQL标准。在MySQL数据库中,SQL 语句分为五大类:
- DCL(Data Control Language):数据控制语言,定义对
数据库、表、字段、用户的访问权限和安全级别,如grant、revoke、transaction、control、commit、rollback、savepoint等 - DDL(Data Definition Language):数据定义语言,定义对
数据库对象(库、表、列、索引)的操作,如:create、drop、alter、rename、 truncate等 - DML(Data Manipulation Language): 数据操作语言,定义对
数据库记录的操作,如:insert、delete、update、select等 - DQL(Data Query Language):数据查询语言,用来查询记录(数据)
- TCL:事务控制语句,例如 commit、rollback、setpoint 等语句属于这个分类
SQL语句可单行或多行书写,以“;”结尾
/* */ 和// 为多行注释
-- 和 # 为 单行注释
带有通配符的条件:
%:匹配任意零个或多个字符
_ :匹配任意单个字符
MySQL中 sql 语句的反引号,可以避免一些与SQL语法冲突的问题,同时可以使代码更加规范化和易读性更强
eg.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| testdb |
+--------------------+
mysql> select name, address from `table`;
# table若当做表名但其为关键字回报错,加上反引号可以避免与SQL关键字的冲突
命令:
- 退出:
退出:exit quit \q
- 清屏:
清屏:\! cls
常用命令:
\G:表示将查询结果进行按列打印,即将查到的结构旋转90度变成纵向显示,不需要分号
\g: #相当于分号
\! 、cls :#清屏
exit、quit、\q :#退出
1.3 MySQL字符集
MySQL字符集包括字符集(CHARACTER)和排序规则(校对规则)(COLLATION)两个概念
1.3.1 字符集
Character Set(字符集):是字符的编码规则,规定了字符在数据库中的存储格式,比如占多少空间,支持哪些字符等
latin1 支持西欧字符、希腊字符等
gbk 支持中文简体字符,但是不是国际通用字符集
big5 支持中文繁体字符
utf8 几乎支持世界所有国家的字符。
utf8mb4 完全兼容 UTF-8,用四个字节存储更多的字符
查看所有支持的字符集
# 格式1:
mysql> show character set;
+----------+---------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+---------------------------+---------------------+--------+
| armscii8 | ARMSCII-8 Armenian | armscii8_general_ci | 1 |
| ascii | US ASCII | ascii_general_ci | 1 |
| big5 | Big5 Traditional Chinese | big5_chinese_ci | 2 |
| binary | Binary pseudo charset | binary | 1 |
…………
# 字段含义
# Charset: 字符集的名称;
# Description:字符集的简单描述;
# Default collation:该字符集的默认字符序;
# Maxlen:该字符集中字符最大存储长度
# 格式2:
# \G表示将查询结果进行按列打印,即将查到的结构旋转90度变成纵向显示,不需要分号
mysql> show character set\G
*************************** 1. row ***************************Charset: armscii8Description: ARMSCII-8 Armenian
Default collation: armscii8_general_ciMaxlen: 1
*************************** 2. row ***************************Charset: asciiDescription: US ASCII
Default collation: ascii_general_ciMaxlen: 1
*************************** 3. row ***************************Charset: big5Description: Big5 Traditional Chinese
Default collation: big5_chinese_ciMaxlen: 2
*************************** 4. row ***************************Charset: binaryDescription: Binary pseudo charset
Default collation: binaryMaxlen: 1
……
MySQL数据库在开发运维中,字符集选用规则如下:
- 如果系统开发面向国外业务,需要处理不同国家、不同语言,则应该选择utf-8或者utf8mb4
- 如果只需要支持中文,没有国外业务,则为了性能考虑,可以采用GBK
查看指定字符集
mysql> show character set like 'gbk';
+---------+------------------------+-------------------+--------+
| Charset | Description | Default collation | Maxlen |
+---------+------------------------+-------------------+--------+
| gbk | GBK Simplified Chinese | gbk_chinese_ci | 2 |
+---------+------------------------+-------------------+--------+
1 row in set (0.00 sec)mysql> show character set like 'utf%';
+---------+------------------+--------------------+--------+
| Charset | Description | Default collation | Maxlen |
+---------+------------------+--------------------+--------+
| utf16 | UTF-16 Unicode | utf16_general_ci | 4 |
| utf16le | UTF-16LE Unicode | utf16le_general_ci | 4 |
| utf32 | UTF-32 Unicode | utf32_general_ci | 4 |
| utf8mb3 | UTF-8 Unicode | utf8mb3_general_ci | 3 |
| utf8mb4 | UTF-8 Unicode | utf8mb4_0900_ai_ci | 4 |
+---------+------------------+--------------------+--------+
1.3.2 字符序
字符序就是字符排序的规则集合
- MySQL字符序命名规则:
- 以字符序对应的字符集名称开头
- 以国家名居中(或以general居中)
- 后缀:
- bin:二进制;
- ci:大小写不敏感;
- cs:大小写敏感;
- ai:口音(Accent)不敏感;
- as:口音敏感;
- ks:假名(Kanatype)敏感
# 查看支持的字符序
mysql> show collation;# 字段含义# Collation:字符序名称# Charset:该字符序关联的字符集# Id:字符序ID# Default:该字符序是否是所关联的字符集的默认字符序armscii8_general_ci就是armscii8的默 认字符序,而armscii8_bin就不是;# Compiled:字符集是否已编译到服务器中# Sortlen:这与对以字符集表示的字符串进行排序所需的内存量有关# Pad_attribute:这表明了字符序在比较字符串时对末尾padding的处理。NO PAD表明在比较字符串 时,末尾的padding也会考虑进去,否则不考虑
指定条件查询
mysql> show collation where charset = "utf8mb4";
查看当前字符集的设置:
mysql> show variables like 'character_set%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 # 重要 数据库默认使用的字符集 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 # 重要 服务器默认的字符集 |
| character_set_system | utf8mb3 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
二、数据库操作
# 新建数据库
create database 数据库名# 设为当前数据库
use 数据库名# 查看当前使用的数据库
select database();# 显示所有数据库
show databases;# 删除数据库
drop database 数据库名# 查看当前登录的用户及主机名
select user();
2.1 数据库常用操作命令
数据库的登录及退出
mysql -uroot -p #登录
exit quit \q #退出
查看当前数据库
select database();
mysql> select database();
+------------+
| database() |
+------------+
| NULL |
+------------+
切换数据库
use 数据库名
mysql> use testdb;
Database changed
mysql> select database(); # 再次查看
+------------+
| database() |
+------------+
| testdb |
+------------+
显示时间
mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2023-02-10 09:39:14 |
+---------------------+
1 row in set (0.00 sec)
显示数据库版本
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.37 |
+-----------+
1 row in set (0.00 sec)
2.2 创建库 (create database 数据库名)
- 数据库命名尽量不超过30个字符
- 数据库命名一般为项目名称+代表库含义的简写,比如 IM 项目的工作流数据库,可以是 im_flow
- 命名应使用小写
- 在创建数据库或查看创建数据库语句时,database没有s
mysql> create database mydb1_test;
Query OK, 1 row affected (0.04 sec)
若数据库已存在,则报错
2.3 查看库 (show databases)
show databases [like 条件];
注意有 s
mysql> show databases; #注意有 s
+--------------------+
| Database |
+--------------------+
| information_schema | #主要存储了系统中的一些数据库对象信息
| mysql | #系统的用户权限信息及帮助信息
| performance_schema | #主要存储数据库服务器的性能参数
| sys | #通过视图的形式把information_schema 和performance_schema结合起来
+--------------------+
4 rows in set (0.26 sec)mysql> select database(); #查看当前库
+------------+
| database() |
+------------+
| NULL |
+------------+
1 row in set (0.01 sec)# 使用条件查看
mysql> show databases like 'sys';
+----------------+
| Database (sys) |
+----------------+
| sys |
+----------------+
1 row in set (0.00 sec)
Information_schema: 主要存储了系统中的一些数据库对象信息,如:用户表信息、列信息、权限信息、字符集信息、分区信息等。(数据字典表)
performance_schema:主要存储数据库服务器的性能参数
mysql: 存储了系统的用户权限信息及帮助信息
sys: 5.7新增,之前版本需要手工导入。这个库是通过视图的形式把information_schema 和performance_schema结合起来,查询出更加令人容易理解的数据
2.4 删除库 (drop database 数据库名)
mysql> drop database testdb;
Query OK, 0 rows affected (0.01 sec)mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
2.5 切换库(use 数据库名)
mysql> use mydb1_test;
Database changed
# 查看当前用户
mysql> select database();
+------------+
| database() |
+------------+
| mydb1_test |
+------------+
1 row in set (0.00 sec)
2.6 数据库对象
组成:

数据库对象的命名规则:
- 命名使用具有意义的英文词汇,词汇中间以下划线分隔
- 名称由字母、数字、#、下划线、$组成,必须以英文字母开头
- 不要使用 MySQL 的保留字
- 所有数据库对象使用小写字母,实际上MySQL中是可以设置大小写是否敏感的,为了保证统一性应使用小写表示
- 在同一个数据库对象集合内对象不能同名
生产中对象命名规范:
- 数据库:
- 数据库命名尽量不超过30个字符
- 数据库命名一般为 项目名称+代表库 含义的简写,比如IM项目的工作流数据库,可以是 im_flow
- 命名应使用小写
- 表:
- 常规表:以t_开头,t代表table的意思,命名规则即 t + 模块(包含模块含义的简写)+ 表(包含表含义的简写),比如用户模块的教育信息表:t_user_eduinfo
- 临时表:temp 前缀+模块+表+日期后缀:temp_user_eduinfo_20240520
- 备份表(用于保存和归档历史数据或者作为灾备恢复的数据)命名规则,bak前缀+模块+表+日期后缀:bak_user_eduinfo_20231219
- 同一个模块的表尽可能使用相同的前缀,表名称尽可能表达含义
- 多个单词以下划线 _ 分隔
- 常规表表名尽量不超过30个字符,temp 表和 bak 表视情况而定,也尽量简短为宜,命名应使用小写
2.7 数据库字典
-
数据字典:类似于系统编目或花名册,它保存数据库服务器上的元数据信息(数据库的整体属性信息)
-
元数据(meta data):即“data about data” 关于数据的数据,理解为描述数据的数据,内容包括:数据库的属性信息、数据表的属性信息、字段的属性信息、视图的属性信息、用户信息、统计类信息等。
-
information_schema 数据库是MySQL系统自带的数据库,它提供了数据库元数据的访问方式
mysql> use information_schema;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -ADatabase changed
mysql> show tables;
+---------------------------------------+
| Tables_in_information_schema |
+---------------------------------------+
| ADMINISTRABLE_ROLE_AUTHORIZATIONS |
| APPLICABLE_ROLES |
| CHARACTER_SETS |
| CHECK_CONSTRAINTS |
| COLLATIONS |
| COLLATION_CHARACTER_SET_APPLICABILITY |
| COLUMNS | #存放数据库里所有的列信息
| COLUMNS_EXTENSIONS |
| COLUMN_PRIVILEGES |
| COLUMN_STATISTICS |
| ENABLED_ROLES |
| ENGINES |
| EVENTS |
| FILES |
| INNODB_BUFFER_PAGE |
| INNODB_BUFFER_PAGE_LRU |
| INNODB_BUFFER_POOL_STATS |
| INNODB_CACHED_INDEXES |
| INNODB_CMP |
| INNODB_CMPMEM |
| INNODB_CMPMEM_RESET |
| INNODB_CMP_PER_INDEX |
| INNODB_CMP_PER_INDEX_RESET |
| INNODB_CMP_RESET |
| INNODB_COLUMNS |
| INNODB_DATAFILES |
| INNODB_FIELDS |
| INNODB_FOREIGN |
| INNODB_FOREIGN_COLS |
| INNODB_FT_BEING_DELETED |
| INNODB_FT_CONFIG |
| INNODB_FT_DEFAULT_STOPWORD |
| INNODB_FT_DELETED |
| INNODB_FT_INDEX_CACHE |
| INNODB_FT_INDEX_TABLE |
| INNODB_INDEXES |
| INNODB_METRICS |
| INNODB_SESSION_TEMP_TABLESPACES |
| INNODB_TABLES |
| INNODB_TABLESPACES |
| INNODB_TABLESPACES_BRIEF |
| INNODB_TABLESTATS |
| INNODB_TEMP_TABLE_INFO |
| INNODB_TRX |
| INNODB_VIRTUAL |
| JSON_DUALITY_VIEWS |
| JSON_DUALITY_VIEW_COLUMNS |
| JSON_DUALITY_VIEW_LINKS |
| JSON_DUALITY_VIEW_TABLES |
| KEYWORDS |
| KEY_COLUMN_USAGE | #存放数据库所有的主外键
| LIBRARIES |
| OPTIMIZER_TRACE |
| PARAMETERS |
| PARTITIONS |
| PLUGINS |
| PROCESSLIST |
| PROFILING |
| REFERENTIAL_CONSTRAINTS |
| RESOURCE_GROUPS |
| ROLE_COLUMN_GRANTS |
| ROLE_ROUTINE_GRANTS |
| ROLE_TABLE_GRANTS |
| ROUTINES | #存放数据库里所有存储过程和函数
| ROUTINE_LIBRARIES |
| SCHEMATA | #存放数据库里所有的数据库信息
| SCHEMATA_EXTENSIONS |
| SCHEMA_PRIVILEGES |
| STATISTICS | #存放了数据表的索引
| ST_GEOMETRY_COLUMNS |
| ST_SPATIAL_REFERENCE_SYSTEMS |
| ST_UNITS_OF_MEASURE |
| TABLES | #存放数据库里所有的数据表、以及每个表所在数据库
| TABLESPACES_EXTENSIONS |
| TABLES_EXTENSIONS |
| TABLE_CONSTRAINTS | #存放数据库全部约束
| TABLE_CONSTRAINTS_EXTENSIONS |
| TABLE_PRIVILEGES |
| TRIGGERS | #存放数据库里所有的触发器
| USER_ATTRIBUTES |
| USER_PRIVILEGES |
| VIEWS | #存放数据库里所有的视图信息
| VIEW_ROUTINE_USAGE |
| VIEW_TABLE_USAGE |
+---------------------------------------+
84 rows in set (0.002 sec)
常用表解释:
tables-存放数据库里所有的数据表、以及每个表所在数据库
schemata-存放数据库里所有的数据库信息
views-存放数据库里所有的视图信息
columns-存放数据库里所有的列信息
triggers-存放数据库里所有的触发器
routines-存放数据库里所有存储过程和函数
key_column_usage-存放数据库所有的主外键
table_constraints-存放数据库全部约束
statistics-存放了数据表的索引
……
三、表的基本操作
# 新建表
create tables 表名(列名1 类型 , 列名2 类型 ……);# 查看表各列信息
{describe|desc}表名[列名];
# or
show columns from 表名称;
# 查看所有表
show tables [from 数据库名][like wild]; # 删除表
drop table if exists 表名; # 修改表名
alter table 旧表名 rename 新表名;
# or
rename table 表名 to 新表名;# 表中添加新列
alter table 表名 add 新列名 列类型 [after|first] 列名; (after为之后)# 删除列
alter table 表名 drop 列名;# 修改列名
alter table 表名 change 旧列名 新列名 列类型;# 修改列类型
alter table 表名 modify 列名 列类型;# 修改列位置
alter table 表名 modify 列名 列类型 after 某列;
3.1 数据类型
类型组成:数字、文本、日期/时间类型
| 数据类型 | 字节数e | 备注 |
|---|---|---|
| int | 4 | 整型 [-2147483648,2147483647] |
| float | 4 | 单精度浮点型 |
| double | 8 | 双精度浮点型 |
| char | 文本型 保存固定长度的字符串 | |
| varchar | 保存可变长度的字符串 | |
| text | 存放最大长度为 65,535 个字符的字符串 | |
| date | 3 | 存储日期值(yyyy-MM-dd) |
| time | 3 | 存储时分秒(HH:mm:ss) |
| year | 1 | 存储年(yyyy) |
| datetime | 8 | 存储日期+时间(yyyy-MM-dd HH:mm:ss ) |
| timestamp | 4 | 存储日期+时间,可作时间戳(yyyy-MM-dd HH:mm:ss) |
| varchar | 保存可变长度的字符串 |
可以使用float(M,D)、double(M,D)格式限制宽度按(M)和精度(D),如float(3,2),不指定M、D的时,会按照实际的精度来处理
3.2 创建表 (create table 表名 (表选项))
create table 表名 (表选项)
表定义选项格式为:
列名1 列类型1 约束, 列名2 列类型2 约束,……
表的名称命名规范:
- 常规表:以 t_ 开头,t 代表 table 的意思,命名规则即 t + 模块(包含模块含义的简写)+ 表(包含表含义的简写),比如用户模块的教育信息表:t_user_eduinfo
- 临时表:temp 前缀 + 模块 + 表 + 日期后缀:temp_user_eduinfo_20240520
- 备份表(用于保存和归档历史数据或者作为灾备恢复的数据)命名规则,bak 前缀 + 模块 + 表 + 日期后缀:bak_user_eduinfo_20231219
- 同一个模块的表尽可能使用相同的前缀,表名称尽可能表达含义
- 多个单词以下划线 _ 分隔
- 常规表表名尽量不超过30个字符,temp 表和 bak 表视情况而定,也尽量简短为宜,命名应使用小写
# 如果没有选择数据库,就会抛出 No database selected 的错误
mysql> select database(); # 查看当前数据库mysql> create database mydb2_stuinfo; # 创建数据库
Query OK, 1 row affected (0.02 sec)mysql> use mydb2_stuinfo; # 使用数据库
Database changedmysql> create table t1(float_num float(10,2),double_num double(20,2),decimal_num decimal(20,2));
Query OK, 0 rows affected, 2 warnings (0.11 sec)mysql> show tables;
+----------------------+
| Tables_in_mydb1_test |
+----------------------+
| t1 |
+----------------------+
1 row in set (0.07 sec)mysql> desc t1; #或者 show columns from 表名称;
+-------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+-------+
| float_num | float(10,2) | YES | | NULL | |
| double_num | double(20,2) | YES | | NULL | |
| decimal_num | decimal(20,2) | YES | | NULL | |
+-------------+---------------+------+-----+---------+-------+
3 rows in set (0.10 sec)
字段意义分析:
Field :字段名称
type:字段类型
null:是否允许为空
key:索引类型
default:默认值
extra:填充
3.3 查看表(show/desc)
- show 语句:显示当前数据库中已有的数据表
show tables [from 数据库名][like wild];
mysql> show tables;
+-------------------------+
| Tables_in_mydb2_stuinfo |
+-------------------------+
| class1 |
| student1 |
+-------------------------+
2 rows in set (0.00 sec)mysql> show tables from mydb3_employee; # 查看另一个库的表示信息
+--------------------------+
| Tables_in_mydb3_employee |
+--------------------------+
| tb1 |
+--------------------------+
1 row in set (0.00 sec)
- describe 语句:查看数据表中各列的信息
{describe|desc}表名[列名];
# or
show columns from 表名称;
mysql> desc student1;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(30) | YES | | NULL | |
| sex | char(2) | YES | | NULL | |
| age | int unsigned | YES | | NULL | |
| score | float | YES | | NULL | |
| addr | varchar(50) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
6 rows in set (0.00 sec)mysql> show columns from student1;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(30) | YES | | NULL | |
| sex | char(2) | YES | | NULL | |
| age | int unsigned | YES | | NULL | |
| score | float | YES | | NULL | |
| addr | varchar(50) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
3.4 删除表(drop table [if exists] 表名;)
用户必须拥有执行 drop table 命令的权限,否则数据表不会被删除
drop table [if exists] 表名;
推荐使用 if exists 字句,即先判断是否存在,存在则删除
mysql> drop table if exists tb1;
Query OK, 0 rows affected (0.01 sec)
删除的注意事项:
- 删除数据库表之前,一定要备份数据,以免数据丢失
- 在删除数据库表之前,要确保该表没有被其他的表所引用,否则可能会破坏外键约束
- 在删除数据库表之前,要确保该表的数据已经被清空,否则会破坏外键约束
- 在删除数据库表之前,要确保该表的所有索引都已经被删除。如果还存在索引,可能会导致删除失败
- 在删除数据库表之前,要确保该表的所有相关程序已经停止运行,以免影响其他程序的正常运行。
3.5 修改表
3.5.1 修改表名(alter/rename;)
- 更改表名(重命名):
# 法1:
alter table 表名 rename 新表名;
# 法2:
rename table 表名 to 新表名;
3.5.2 添加新列(alter talble 表名 add 新列名 列类型;)
- 添加新列
alter table 表名 add 新列名 列类型 [after|first] 列名;# after:在指定列之后插入新列
# first:在第一列插入新列
# 注意:无 before关键字
# 例:增加一列 password
mysql> alter table student1 add password char(8);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0# 注意:数据库操作后得到的反馈,表明操作的结果。这个信息表示:# Records: 0: 表示成功导入或处理的记录总数是0条# Duplicates: 0: 表示在操作过程中没有发现重复的记录# Warnings: 0: 表示在操作过程中没有产生任何警告
3.5.3 删除列(alter table 表名 drop 列名;)
删除列
alter table 表名 DROP 列名;
# 例:删除上例的notes列
mysql> alter table student1 drop notes;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
3.5.4 修改列名(alter table 表名 change 旧列名 新列名 列类型;)
修改列名
alter table 表名 change 旧列名 新列名 列类型;
mysql> alter table student1 change password passwd char(8); # 改名
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
3.5.5 修改列类型(alter table 表名 modify 列名 列类型;)
修改列类型
alter table 表名 modify 列名 列类型;
mysql> alter table student1 modify birthday date; # 修改
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
3.5.6 修改列位置(alter table 表名 modify 列名 列类型 after 某列;)
修改列位置
alter table 表名 modify 列名 列类型 after 某列;
# 例:添加新列
mysql> alter table student1 add notes varchar(30) after name;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0# 将notes移动到最后
mysql> alter table student1 modify notes varchar(30) after birthday;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0# 删除该列
mysql> alter table student1 drop notes;
3.6 复制表的结构(create/insert into)
方法一:在 create table 语句的末尾添加 like 子句,可以将源表的表结构复制到新表中
create table 新表名 like 源表
注意:只是复制结构框架
方法二:在 create table 语句的末尾添加一个 select 语句,可以实现表结构的复制,甚至可以将源表的表记录拷贝到新表中
create table 新表名 select * from 源表
方法三:如果已经存在一张结构一致的表,复制数据(insert into)
mysql> select * from student2;
Empty set (0.00 sec)mysql> insert into student2 select * from student1;
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
四、表的约束
4.1 概念与语法
约束:约束是 在表上 强制执行 的数据校验规则,本质上是 Mysql 通过 限制用户操作 的方式,来达到 维护数据本身安全及数据完整性 的一套方案
数据的完整性要从以下四个方面考虑:
- 实体完整性(Entity Integrity):例如,同一个表中,不能存在两条完全相同无法区分的记录
- 域完整性(Domain Integrity):例如,年龄范围 0-120,性别范围“男/女”
- 引用完整性(Referential Integrity):例如,员工所在部门,在部门表中要能找到这个部门
- 用户自定义完整性(User-defined Integrity):例如,用户名唯一、密码不能为空等,本部门经理的工资不得高于本部门职工的平均工资的5倍。
常见的约束:
- 非空约束 not null
- 默认值约束 default
- 主键约束 primary key
- 外键约束
- 唯一约束
- 检查约束
列级约束:在定义列的同时定义约束
create table 表名 (列名 类型 约束 )
表级约束:在定义了所有列之后定义的约束
create table 表名 constraint 约束名 约束类型 (列信息)
创建表之后添加约束:
alter table 表名 add constraint 约束名 约束类型(要约束的列名)
创建表之后修改约束:
mysql> alter table <数据表名> change column <字段名> <字段名> <数据类型> not null;# 也可以通过modify修改
mysql> alter table <数据表名> modify <字段名> <数据类型> not null;
4.2 非空约束 not null
作用:限定 某个字段/某列的值 不允许为空
如果不写约束,默认为 null
若需要某些字段必须写入,应该怎么处理,如:创建一个班级表,包含班级名和班级所在的教室,站在正常的业务逻辑中:如果班级没有名字,你不知道你在哪个班级,如果教室名字可以为空,就不知道在哪上课,所以我们在设计数据库表的时候,一定要在表中进行限制,满足上面条件的数据就不能插入到表中,这就是“约束
- 删除非空约束 not null
mysql> alter table <数据表名> modify <字段名> <数据类型> null;
# 或者
mysql> alter table <数据表名> modify <字段名> <数据类型>;
4.3 默认值约束 default’ ’
作用:给某个字段/某列指定默认值,一旦设置默认值,在插入数据时,如果此字段没有显式赋值,则赋值为默认值
not null 和 defalut 一般不需要同时出现,因为 default 本身有默认值,不会为空
eg.
mysql> create table teacher1(id int not null, name varchar(30) not null, sex char(2) default '女', age int);
Query OK, 0 rows affected (0.03 sec)mysql> desc test;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int | NO | | NULL | |
| name | varchar(30) | NO | | NULL | |
| sex | char(2) | NO | | 女 | |
| age | int unsigned | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
4.4 列描述 comment ’ ’
列描述没有实际含义,专门用来描述字段,会根据表创建语句保存,供操作者来查看该列的含义
mysql> create table myclass2( class_name varchar(20) not null comment '教室',class_room varchar(20) default '计科2');
Query OK, 0 rows affected (0.065 sec)mysql> desc myclass2;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| class_name | varchar(20) | NO | | NULL | |
| class_room | varchar(20) | YES | | 计科2 | |
+------------+-------------+------+-----+---------+-------+
2 rows in set (0.003 sec)mysql> show create table myclass2\G
*************************** 1. row ***************************Table: myclass2
Create Table: CREATE TABLE `myclass2` (`class_name` varchar(20) NOT NULL COMMENT '教室',`class_room` varchar(20) DEFAULT '计科2'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.001 sec)
4.5 主键约束 primary key
作用:数据库存储数据不是唯一的目的,还要考虑到提取数据,一般要求 数据库表中的记录要有一个特定的唯一标识 ,来表示唯一性,这个唯一的特定标识就是主键,类似于序号学号这样的唯一标识,可以根据主键来唯一地筛选出一条记录
主键:primary key,用来唯一的约束该字段里面的数据
特点:
- 主键字段不能为空,不能重复
- 一张表中最多只能有一个主键
- 主键所在的列通常是整数类型
- 主键约束是最频繁的约束
不要修改主键字段的值。因为主键是数据记录的唯一标识,如果修改了主键的 值,就有可能会破坏数据的完整性。
- 创建时添加主键
mysql> create table t1 ( id int unsigned primary key comment '学号不能为空', name varchar(20) not null ,sex char(2) default '男');
Query OK, 0 rows affected (0.02 sec)mysql> desc t1;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int unsigned | NO | PRI | NULL | | #主键标识
| name | varchar(30) | NO | | NULL | |
| sex | char(2) | YES | | 男 | |
+-------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)mysql> insert into t1 values(1,'孙文','女');
Query OK, 1 row affected (0.00 sec)mysql> select * from t1;
+----+--------+------+
| id | name | sex |
+----+--------+------+
| 1 | 孙文 | 女 |
+----+--------+------+
1 row in set (0.00 sec)
mysql> insert into t1(id,name) values(2,'李文华');
Query OK, 1 row affected (0.00 sec)
mysql> select * from t1;
+----+--------+------+
| id | name | sex |
+----+--------+------+
| 1 | 孙文 | 女 |
+----+--------+------+
| 2 | 李文华 | 男 |
+----+--------+------+
2 row in set (0.00 sec)
mysql> insert into t1(id,name) values(1,'黎明'); #再次插入出错,因为需要保持唯一性
ERROR 1062 (23000): Duplicate entry '1' for key 't1.PRIMARY'
再次插入出错,因为需要保持唯一性
- 修改表,追加主键
mysql> alter table teacher1 add primary key(id);
Query OK, 0 rows affected (0.07 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> desc teacher1;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(80) | NO | | NULL | |
| sex | char(2) | YES | | 女 | |
| age | int | NO | | 18 | |
+-------+--------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
如果该字段内有重复值,则不能以该字段新增为主键,必须先把重复的数据去掉然后才能添加该列为主键
- 删除主键:
alter table 表名 drop primary key;mysql> desc t5;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
| salary | float | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
3 rows in set (0.002 sec)mysql> alter table t5 drop primary key;
Query OK, 1 row affected (0.076 sec)
Records: 1 Duplicates: 0 Warnings: 0mysql> desc t5;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | int | NO | | NULL | |
| name | varchar(20) | YES | | NULL | |
| salary | float | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
3 rows in set (0.001 sec)
4.5.1 复合主键 primary key (字段1,字段2)
复合主键:如果有多个字段作为主键,可以使用复合主键,这些字段合在一起是一个主键,也就是让多个字段联合在一起作为唯一标识,单个字段主键重复是没有问题的,只要不是成为复合主键的字段一起冲突就行
mysql> create table t2 (id int, hostname varchar(10), ip varchar(20), port int unsigned, primary key (ip,port)); #复合主键
Query OK, 0 rows affected (0.023 sec)mysql> desc t2;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| hostname | varchar(10) | YES | | NULL | |
| ip | varchar(20) | NO | PRI | NULL | | #将ip字段和port字段复合起来
| port | int unsigned | NO | PRI | NULL | |
+----------+--------------+------+-----+---------+-------+
4 rows in set (0.002 sec)mysql> insert into t2 values(1,'node1','192,168,48,2',120);
Query OK, 1 row affected (0.005 sec)mysql> select * from t2;
+------+----------+--------------+------+
| id | hostname | ip | port |
+------+----------+--------------+------+
| 1 | node1 | 192,168,48,2 | 120 |
+------+----------+--------------+------+
1 row in set (0.001 sec)mysql> insert into t2 values(2,'node2','192,168,48,3',120);
Query OK, 1 row affected (0.002 sec) # 可以单个记录重复mysql> insert into t2 values(3,'node2','192,168,48,2',120); # 复合主键一起冲突,报错
ERROR 1062 (23000): Duplicate entry '192,168,48,2-120' for key 't2.PRIMARY'
4.5.2 主键自增长 auto_increment
作用:给主键添加自增长的数值
注意:
- 自增长字段必须是整数,自增长字段可以 不设置初始值,默认从1开始递增.
- 自增长字段也可以插入数据,只要不与已有数据重复即可,之后新增数据会从最大值开始递增
- 任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)
- 一张表当中最多只能有一个自增长的列
- 约束的字段必须具备 NOT NULL 属性
mysql> select * from t5;
+----+------+--------+
| id | name | salary |
+----+------+--------+
| 1 | Li | 5984 |
+----+------+--------+
1 row in set (0.000 sec)# 先增加主键
mysql> alter table t5 modify id int primary key;
Query OK, 0 rows affected (0.092 sec)
Records: 0 Duplicates: 0 Warnings: 0# 设置自增长
mysql> alter table t5 modify id int auto_increment;
Query OK, 1 row affected (0.022 sec)
Records: 1 Duplicates: 0 Warnings: 0mysql> desc t5;
+--------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
| salary | float | YES | | NULL | |
+--------+-------------+------+-----+---------+----------------+
3 rows in set (0.002 sec)mysql> insert into t5(name) values('关六');
Query OK, 1 row affected (0.003 sec)mysql> select * from t5;
+----+--------+--------+
| id | name | salary |
+----+--------+--------+
| 1 | Li | 5984 |
| 2 | 关六 | NULL |
+----+--------+--------+
2 rows in set (0.001 sec)
指定自增长的起始值:如果第一条记录设置了该字段的初始值,那么新增加的记录就从这个初始值开始自增
例如,如果表中插入的第一条记录的 id 值设置为 5,那么再插入记录时,id 值就会从 5 开始往上增加
4.6 外键约束 foreign key references
作用:限定某个表的某个字段的引用完整性(Referential Integrity:例如:员工所在部门,在部门表中要能找到这个部门)
- 主表(父表):被引用的表、被参考的表
- 从表(子表):引用别人的表,参考别人的表
- 外键:从表中的某个字段引用自主表的某个字段或多个字段
- 引用键:主表被引用的字段
外键约束主要定义在从表上,主表则必须是有主键约束或唯一键约束,当定义外键后,要求外键列数据必须在主表的主键列存在或为 NULL
格式:
foreign key (从表的字段名称) references 主表名字(主表的字段名称) # 建立外键关联
- 主表必须已经存在于数据库中,或者是当前正在创建的表。如果是后一种情况,则主表与从表是同一个表,这样的表称为自参照表,这种结构称为自参照完整性
- 必须为主表定义主键
- 主键不能包含空值,但允许在外键中出现空值。也就是说,只要外键的每个非空值出现在指定的主键中,这个外键的内容就是正确的
- 在主表的表名后面指定列名或列名的组合。这个列或列的组合必须是主表的主键或候选键
- 外键中列的数目必须和主表的主键中列的数目相同
- 外键中列的数据类型必须和主表主键中对应列的数据类型相同
定义从表的时候,设置外键其实就是设置了一个关系,在从表当中插入数据的时候,会对插入数据进行校验,校验插入的数据是否存在于主表字段当中,外键就是增加了表和表之间的约束关系
# 定义主表
mysql> create table myclass3(id int primary key, name varchar(20) not null comment '班级名');
Query OK, 0 rows affected (0.026 sec)mysql> desc myclass3;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(20) | NO | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.002 sec)# 定义从表: 外键:foreign key references
mysql> create table myclass3_stu( id int primary key, name varchar(30) not null comment '学生名', class_id int, foreign key (class_id) references myclass3(id) );
Query OK, 0 rows affected (0.015 sec)mysql> desc myclass3_stu;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(30) | NO | | NULL | |
| class_id | int | YES | MUL | NULL | |
+----------+-------------+------+-----+---------+-------+
3 rows in set (0.002 sec)# 主表中插入数据
mysql> insert into myclass3 values(10,'C++'),(20,'Java');
Query OK, 2 rows affected (0.003 sec)
Records: 2 Duplicates: 0 Warnings: 0mysql> select * from myclass3;
+----+------+
| id | name |
+----+------+
| 10 | C++ |
| 20 | Java |
+----+------+
2 rows in set (0.000 sec)# 从表中正常插入数据:
mysql> insert into myclass3_stu values(1,'Li',10),(2,'Sun',20);
Query OK, 2 rows affected (0.004 sec)
Records: 2 Duplicates: 0 Warnings: 0mysql> select * from myclass3_stu;
+----+------+----------+
| id | name | class_id |
+----+------+----------+
| 1 | Li | 10 |
| 2 | Sun | 20 |
+----+------+----------+
2 rows in set (0.001 sec)# 从表中插入没有班级的记录,受外键控制,报错
mysql> insert into myclass3_stu values(3,'wang',30);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`d1`.`myclass3_stu`, CONSTRAINT `myclass3_stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `myclass3` (`id`))# 从表中,收到外键控制,可以使用NULL替代,表示没有分配班级
mysql> insert into myclass3_stu values(3,'wang',null);
Query OK, 1 row affected (0.004 sec)mysql> select * from myclass3_stu;
+----+------+----------+
| id | name | class_id |
+----+------+----------+
| 1 | Li | 10 |
| 2 | Sun | 20 |
| 3 | wang | NULL |
+----+------+----------+
3 rows in set (0.000 sec)
在这里插入代码片
4.7 唯一性约束 unique
产生原因:一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键,唯一键就可以解决表中有多个字段需要唯一性约束的问题
作用:限制某个字段/某列的值不能重复
唯一键(unique)和主键(primary key)的关系:
- 主键只能有一个,唯一键能设置多个
- 主键用来查找,唯一键用来保证数据的完整性
创建表时实现:
mysql> create database d1;
Query OK, 1 row affected (0.007 sec)mysql> use d1;
Database changed
mysql> create table t4( id int primary key, name varchar(20) unique comment '名子不能重名,可以为空' );
Query OK, 0 rows affected (0.012 sec)mysql> desc t4;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(20) | YES | UNI | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.002 sec)mysql> insert into t4 values(1,'刘文');
Query OK, 1 row affected (0.007 sec)# 唯一键数据重复,插入失败
mysql> insert into t4 values(1,'刘文');
ERROR 1062 (23000): Duplicate entry '1' for key 't4.PRIMARY'
mysql> insert into t4 values(2,'张磊');
Query OK, 1 row affected (0.003 sec)mysql> select * from t4;
+----+--------+
| id | name |
+----+--------+
| 1 | 刘文 |
| 2 | 张磊 |
+----+--------+
2 rows in set (0.000 sec
- 唯一键冲突,自增涨字段值不连续
# 设置id列为自增长
mysql> alter table t4 modify id int auto_increment;
Query OK, 2 rows affected (0.071 sec)
Records: 2 Duplicates: 0 Warnings: 0mysql> insert into t4(name) values('张磊磊');
Query OK, 1 row affected (0.004 sec)mysql> select * from t4;
+----+-----------+
| id | name |
+----+-----------+
| 1 | 刘文 |
| 2 | 张磊 |
| 3 | 张磊磊 |
+----+-----------+
3 rows in set (0.001 sec)# 插入一条相同姓名记录
mysql> insert into t4(name) values('张磊磊');
ERROR 1062 (23000): Duplicate entry '张磊磊' for key 't4.name'# 在插入一条记录,由于上述唯一键冲突,自增长会出现不连续
mysql> insert into t4(name) values('钱明');
Query OK, 1 row affected (0.004 sec)mysql> select * from t4;
+----+-----------+
| id | name |
+----+-----------+
| 1 | 刘文 |
| 2 | 张磊 |
| 3 | 张磊磊 |
| 5 | 钱明 |
+----+-----------+
4 rows in set (0.001 sec)
4.8 检查约束 check
作用:检查约束(check)是用来检查数据表中字段值有效性的一种手段,一般用于设置值的范围
- 创建表时设置检查约束:
# 设置约束:check(salary>0 and salary<10000)
mysql> create table t5(id int primary key, name varchar(20), salary float, check(salary>0 and salary<10000) );
Query OK, 0 rows affected (0.023 sec)mysql> desc t5;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
| salary | float | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
3 rows in set (0.002 sec)mysql> insert into t5 values(1,'Li',5984);
Query OK, 1 row affected (0.005 sec)mysql> insert into t5 values(1,'Li',5984);
ERROR 1062 (23000): Duplicate entry '1' for key 't5.PRIMARY'
- 修改表时添加检查约束(add constraint)
# 格式:
alter table 表名 add constraint <检查约束名> check(检查约束);mysql> alter table t5 add constraint check_id check(id>0);
Query OK, 1 row affected (0.023 sec)
Records: 1 Duplicates: 0 Warnings: 0
4.9 删除约束
# 删除 not null约束
alter table 表名 modify 列名 类型;# 删除 unique约束
alter table 表名 drop index 惟一约束名;# 删除 primary key约束
alter table 表名 drop primary key;# 删除 foreign key约束
alter table 表名 drop foreign key 外键名;
五、MySQL库表设计(范式)
5.1 范式概念与三范式小结
范式( Normal Form )是指设计数据库时要遵守的一些原则
三范式小结:
- 1NF:确保
原子性,表中每一个列数据都必须是不可再分的字段 - 2NF:确保
唯一性,每张表都只描述一种业务属性,一张表只描述一件事 - 3NF:确保
独立性,表中除主键外,每个字段之间不存在任何依赖,都是独立的
三大范式之间,是递进的关系,后续的范式都基于前一个范式的基础上推行
5.2 第一范式(1NF)
原则:库表设计时为了确保原子性,其存储数据具备不可再分性
eg.

-
在上述的学生表中,其中有一个
student学生列,这一列存储的数据则明显不符合第一范式:原子性的规定,因为这一列的数据还可以再拆分为姓名、性别、身高三项数据,因此为了符合第一范式,应该将表结构更改为:

-
如果不去拆分列满足第一范式,会造成什么影响?
- 客户端语言和表之间无法很好的生成映射关系
- 查询到数据后,需要处理数据时,还需要对
student字段进行额外拆分 - 插入数据时,对于第一个字段的值还需要先拼装后才能进行写入
5.3 第二范式(2NF)
原则:表中的所有列,其 数据都必须依赖于主键,也就是一张表只存储同一类型的数据,不能有任何一列数据与主键没有关系
eg.

-
虽然此时已经满足了数据库的第一范式,但此刻观察
course课程、score分数这两列数据,跟前面的几列数据实际上依赖关系并不大,同时也由于这样的结构,导致前面几列的数据出现了大量冗余,所以此时可以再次拆分一下表结构:

-
经过上述结构优化后,之前的一张表被拆分成学生表、课程表、成绩表三张,每张表中的
id字段作为主键,其他字段都依赖这个主键。无论在那张表中,都可以通过id主键确定其他字段的信息,每张表的业务属性都具备“唯一性”,也就是每张表都只会描述了“一件事情”,不会存在一张表中会出现两个业务属性
5.4 第三范式(3NF)
原则:表中每一列数据不能与主键之外的字段有直接关系
eg.

- 比如这张学生表,目前即符合第一范式,也符合第二范式,但看最后的两个字段,
department表示当前学生所属的院校,dean则表示这个院系的院长是谁。一般来说,一个学生的院长是谁,首先是取决于学生所在的院系的,因此最后的dean字段明显与department字段存在依赖关系,因此需要进一步调整表结构:

经过进一步的结构优化后,又将原本的学生表拆为了院系表、学生表两张,学生表中则是只存储一个院系ID,由院系表存储院系相关的所有数据。至此,学生表中的每个非主键字段与其他非主键字段之间,都是相互独立的,之间不会再存在任何依赖性,所有的字段都依赖于主键
5.5 巴斯-科德范式(BCNF)
规定了联合主键(多个列组成的主键)中的某列值,不能与联合主键中的其他列存在依赖关系
5.6 第四范式(4NF)- 消除表中的多值依赖关系
多值依赖:表中的字段之间存在一对多的关系,也就是一个字段的具体值会由多个字段来决定(一个表中至少需要有三个独立的字段才会出现多值依赖问题)
- 第四范式就是为了消除表中的多值依赖关系
5.7 第五范式(5NF)/完美范式
建立在
4NF的基础上,进一步消除表中的连接依赖,直到表中的连接依赖都是主键所蕴含的
5.9 第六范式(6NF)/域键范式
域键范式,也被称之为终极范式,但目前也仅有学术机构在研究,在生产环境中实际的用途也不
5.9 反范式 - 不遵循数据库范式设计
不遵循数据库范式设计的结构,就被称为反范式结构。
-
遵循数据库范式设计优点如下:
- 避免了大量的数据冗余
- 节省了大量存储空间
- 表整体结构更为优雅,能让
SQL操作更加便捷且减少出错。

范式概念:
- 第一范式:原子性,每个字段的值不能再分
- 第二范式:唯一性,表内每行数据必须描述同一业务属性的数据
- 第三范式:独立性,表中每个非主键字段之间不能存在依赖性
- 巴斯范式:主键字段独立性,联合主键字段之间不能存在依赖性
- 第四范式:表中字段不能存在多值依赖关系
- 第五范式:表中字段的数据之间不能存在连接依赖关系
- 域键范式:试图研究出一个库表设计时的终极完美范式
六、MySQL数据库账户及授权
6.1 密码策略
查看数据库当前密码策略 — show variables like “%password%”;
mysql> show variables like "%password%";
+----------------------------------------------+-----------------+
| Variable_name | Value |
+----------------------------------------------+-----------------+
| # 是否自动生成RSA密钥对文件caching_sha2_password_auto_generate_rsa_keys | ON |
| # 哈希回合数caching_sha2_password_digest_rounds | 5000 |
| # RSA 私钥文件caching_sha2_password_private_key_path | private_key.pem |
| # RSA 公钥文件caching_sha2_password_public_key_path | public_key.pem |
| # MySQL密码过期时间,单位为天default_password_lifetime | 0 |
| # 超时断开disconnect_on_expired_password | ON |
| # 随机密码长度generated_random_password_length | 20 |
| # 是否支持代理用户控制认证插件mysql_native_password_proxy_users | OFF |
| # 不允许用户使用最近n次使用过的密码password_history | 0 |
| # 修改密码时是否需要提供当前用户使用的密码,OFF不需要,ON需要password_require_current | OFF |
| # 不允许用户使用最近n天内使用过的密码password_reuse_interval | 0 |
| report_password | |
| sha256_password_auto_generate_rsa_keys | ON |
| sha256_password_private_key_path | private_key.pem |
| sha256_password_proxy_users | OFF |
| sha256_password_public_key_path | public_key.pem |
+----------------------------------------------+-----------------+
查看密码设置策略 — SHOW VARIABLES LIKE ‘validate_password%’;
mysql> SHOW VARIABLES LIKE 'validate_password%';
Empty set (0.01 sec)
# 注意:若显示为空,则表示未安装插件mysql> INSTALL COMPONENT 'file://component_validate_password';
Query OK, 0 rows affected (0.01 sec)mysql> show variables like 'validate_password%';
+--------------------------------------+--------+
| Variable_name | Value |
+--------------------------------------+--------+
| # 是否能将密码设置成当前用户名validate_password.check_user_name | ON |
| # 插件用于验证密码强度的字典文件路径,默认为空validate_password.dictionary_file | |
| # 密码最小长度,默认为8,有最小值为4的限制validate_password.length | 8 |
| # 密码至少要包含的小写字母和大写字母的个数validate_password.mixed_case_count | 1 |
| # 密码至少要包含的数字个数validate_password.number_count | 1 |
| # 密码强度检查等级validate_password.policy | MEDIUM |
| # 密码必须包含的特殊字符个数validate_password.special_char_count | 1 |
+--------------------------------------+--------+
7 rows in set (0.00 sec)
- 密码强度检查等级解释(
validate_password.policy)
| 等级 | 检查对象 |
|---|---|
| 0 or LOW | 检查长度 |
| 1 or MEDIUM | 检查长度、数字、大小写、特殊字符 |
| 2 or STRONG | 检查长度、数字、大小写、特殊字符、字典文件 |
- 设置密码强度检查参数 —
set global 参数=值;
mysql> show variables like 'validate_password.%'; # 查看密码策略# 设置密码验证强度检查策略
mysql> set global validate_password.policy=low; # 或0# 设置至少要包含大/小写字母的个数
mysql> set global validate_password.mixed_case_count=0;# 设置至少要包含数字的个数
mysql> set global validate_password.number_count=6;# 设置至少包含特殊字符个数
mysql> set global validate_password.special_char_count=0;# 设置密码长度
mysql> set global validate_password.length=6; mysql> show variables like 'validate_password.%'; # 再次查看
+-------------------------------------------------+-------+
| Variable_name | Value |
+-------------------------------------------------+-------+
| validate_password.changed_characters_percentage | 0 |
| validate_password.check_user_name | ON |
| validate_password.dictionary_file | |
| validate_password.length | 6 |
| validate_password.mixed_case_count | 0 |
| validate_password.number_count | 6 |
| validate_password.policy | LOW |
| validate_password.special_char_count | 0 |
+-------------------------------------------------+-------+
8 rows in set, 1 warning (0.00 sec)mysql> flush privileges; # 刷新权限,生效
Query OK, 0 rows affected (0.01 sec)
修改密码:alter user '用户'@'主机' identified by '密码';
mysql> select user, host, plugin from mysql.user; # 查看root用户信息mysql> alter user 'root'@'localhost' identified by '123456';
# 注意:主机名为localhost,远程主机为%mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)
6.2 登录账户管理
mysql8 的账户权限管理原则:先创建账户,再赋予权限
- 用户信息存放在 mysql 数据库下的 user 表
mysql> select user(); # 查看当前的用户信息mysql> use mysql;mysql> show tables;mysql> desc user;# 查询 MySQL 数据库中 user 系统表中的特定用户信息
mysql> select user,host,authentication_string from user;
- user:用户名
- host:允许该用户连接的主机(% 表示任意主机)
- authentication_string 字段存储的是用户密码的加密哈希值(不是明文密码)
6.3 新建登录账户(create user ‘’@‘’ identified by ‘’)
create user 'username'@'localhost' identified by 'password';
username: 创建的用户名
localhost: 指定该用户在哪个主机上可以登陆,如果是本地用户可用 localhost ,如果想让该用户可以从任意远程主机登陆,可以使用通配符 %
password: 该用户的登陆密码
eg.
mysql> create user 'test1'@'localhost' identified by '123456';
# 注意:密码要符合密码设置规则mysql> select user, host, plugin from mysql.user; # 查看信息
# user:用户名
# host:允许该用户连接的主机(% 表示任意主机)
# plugin:该用户使用的身份验证插件mysql> exit
ByePS C:\Users\Administrator> mysql -u test1 -p
Enter password: ****** # test1账户登录mysql> show databases; # 只能看到有限的库
+--------------------+
| Database |
+--------------------+
| information_schema |
| performance_schema |
+--------------------+
2 rows in set (0.01 sec)
6.4 账户授权(grant)
作用:通过账户权限限制普通账户的工作范围及内容,赋权原则如下:
- root 账号绝对禁止允许任何IP都可以访问,即登录方式不能用%
- 应用账号和管理账号要分离
- 赋权最小化,即一般只给 select 权限,最好不要给 update、insert 等编辑权限
- 密码设置合理
- 定期清理不使用的账户,将其收回权限或删除
常见的用户权限:


- 查看权限
mysql> show grants; # 查看当前账户mysql> show grants for 'test1'@'localhost'; # 查看其它账户权限
+----------------------------------+
| Grants for test1@% |
+----------------------------------+
| GRANT USAGE ON *.* TO `test1`@`localhost` |
+----------------------------------+
1 row in set (0.00 sec)
# 上例显示test账户只有usage默认权限即连接登录的权限
- 赋权语法
grant 权限列表 on 数据库名.表名 to '用户名'@'来源地址' [identified by '密码'];
- 权限列表: 用户的操作权限,如 SELECT , INSERT , UPDATE ,CREATE 等,如果要授予所有的权限则使用 ALL
- 数据库名: * 代表所有数据库
- 表名: * 代表所有数据表
- 用户名:指定哪个用户进行赋权操作
- 来源地址: 指定该用户在哪个主机上可以登陆,如果是本地用户可用 localhost ,如果想让该用户可以从任意远程主机登陆,可以使用通配符 %
- 示例1:赋权 test1 账户 select 查询权限
# 使用root账户登录
mysql -u root -pmysql> grant select on *.* to 'test1'@'localhost'; # 赋予mysql库的查询权限
Query OK, 0 rows affected (0.01 sec)mysql> show grants for 'test1'@'localhost';mysql> select * from mysql.user where user='test1'\G # 查看user表的权限信息mysql> \q
Bye
PS C:\Users\Administrator> mysql -u test1 -p # 重新登录
Enter password: ******mysql> show databases;
- 示例2:创建 test2 账户,设置密码,赋权 select 和 create 权限,仅通过某个网段登录
PS C:\Users\Administrator> mysql -u root -p
Enter password: ******# 需要查本机的IP网段
mysql> create user 'test2'@'10.100.170.%' identified by '123456';mysql> select user, host, plugin from mysql.user;mysql> show grants for 'test2'@'10.100.170.%';mysql> grant select,create on *.* to 'test2'@'10.100.170.%';mysql> show grants for 'test2'@'10.100.170.%';
- 示例3:创建 test3 账户,设置密码,赋与所有权限(all所有权限中不包含给账户赋权的权限grant),仅通过%登录,登录后创建 test4 账户并赋权
PS C:\Users\Administrator> mysql -u root -pmysql> create user 'test3'@'%' identified by '123456';mysql> select user, host, plugin from mysql.user;mysql> show grants for 'test3'@'%';mysql> grant all on *.* to 'test3'@'%';mysql> show grants for 'test3'@'%';mysql> exit
ByePS C:\Users\Administrator> mysql -u test3 -p123456mysql> create database mydbx_temp1;mysql> create user 'test4'@'%' identified by '123456';mysql> select user, host, plugin from mysql.user;mysql> show grants for 'test4'@'%'; # 查看test4账户权限mysql> select user(); # 查看当前登录的账户mysql> grant select on *.* to 'test4'@'%'; # 被拒绝,无权给test4账户赋权
ERROR 1045 (28000): Access denied for user 'test3'@'%' (using password: YES)# 注意:all所有权限中不包含给账户赋权的权限grantmysql> exit
ByePS C:\Users\Administrator> mysql -u root -p # 登录root账户给test3账户赋与给别的账户赋权的权限#### 给test3添加赋权的权限
mysql> grant all on *.* to 'test3'@'%' with grant option; # 给test3添加赋权的权限mysql> exit
ByePS C:\Users\Administrator> mysql -u test3 -p123456 # 登录test3账户mysql> grant select on *.* to 'test4'@'%'; # 给test4赋权
Query OK, 0 rows affected (0.01 sec)
- 注意:若赋权不成功则先给 root 账户增加 system_user 权限
mysql> grant system_user on *.* to 'root'@'localhost'; # 给root赋权system_user权限
# 注意:登录主机是%还是localhost
6.5 回收权限(revoke)
revoke 跟 grant 的语法差不多,只需要把关键字 “to” 换成 “from” 即可
revoke 权限列表/all on 库名.表名 from '用户名'@'来源地址';
# revoke跟grant 的语法差不多,只需要把关键字 “to” 换成 “from” 即可
- 回收所有权限:
PS C:\Users\Administrator> mysql -u root -pmysql> select user, host, plugin , select_priv from mysql.user;
# select_priv查询权限mysql> show grants for 'test4'@'%'; # 查看test4账户的权限mysql> revoke select on *.* from 'test4'@'%'; # 回收select权限mysql> show grants for 'test4'@'%';mysql> revoke all on *.* from 'test3'@'%'; # 回收所有权限mysql> show grants for 'test3'@'%';
6.6 删除账户(drop user ‘’@‘’)
drop user '用户名'@'访问主机名';
- 删除所有账户
mysql> select user, host from mysql.user;mysql> drop user 'test1'@'localhost';
Query OK, 0 rows affected (0.01 sec)mysql> drop user 'test2'@'10.100.170.%';
Query OK, 0 rows affected (0.01 sec)mysql> select user, host from mysql.user;
+------------------+-----------+
| user | host |
+------------------+-----------+
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+------------------+-----------+
4 rows in set (0.00 sec)
练习
# 查
show databases; #查看所有库
select database(); #查看当前库(使用的是函数)
show tables; #查看当前库的所有表
show #查看指定库的所有表#查看表结构
desc 表名; #查看表结构
show columns from 表名; #查看表结构select * from 表名; #查看此表的具体内容(字段、类型、约束)
select user(); #查看当前登录的用户和主机名
show databases; #查看所有库
create database 表名;#创建库
drop 表名; #删除、修改库
select database(); #查看当前正在使用的库
use 库名; #切换当前库
show tables; #查看当前库的所有表
create table 表名(字段[列名] 类型 约束,字段 类型 约束);#创建表#删除、修改表
drop table if exists 表名;
alter table 表名1 rename 表名2;
rename table 表名1 to 表名2#查看指定表的结构
desc 表名;
show columns from 表名;
select * from 表名; #查看指定表的内容alter table 表名 drop 列名 ; #删除表的内容#增加表的内容
alter table 表名 change 列名1 列名2 类型; #修改列名#修改表的内容的列的位置
alter table 表名 add 列名 类型;
alter table 表名 add 列名 类型 after 列名;#指定位置,...之后
alter table 表名 add 列名 类型 first;第一列alter table 表名 modify 列名 新类型;#修改表的内容的列的类型#复制表结构
create table 表2 like 表1; #将表1的结构复制给表2
create table 表2 select * from 表1; #复制表1的结构和内容给表2
insert into 表2 select * from 表1; #复制表1的结构和内容给表2(前提:两个表的结构必须一样)
