1. SQL语句基础
1.2 SQL简介
SQL:结构化查询语言(Structured Query Language),在关系型数据库上执行数据操作、数据检索以及数据维护的标准语言。使用SQL语句,程序员和数据库管理员可以完成如下的任务
改变数据库的结构
更改系统的安全设置
增加用户对数据库或表的许可权限
在数据库中检索需要的信息
对数据库的信息进行更新
1.3 SQL语句分类
-
MySQL致力于支持全套ANSI/ISO SQL标准。在MySQL数据库中,SQL语句主要可以划分为以下几类
-
DDL(Data Definition Language):数据定义语言,定义对数据库对象(库、表、列、索引)的操作,如:CREATE、DROP、ALTER、RENAME、 TRUNCATE等
-
DML(Data Manipulation Language): 数据操作语言,定义对数据库记录的操作,如:INSERT、DELETE、UPDATE、SELECT等
-
DCL(Data Control Language): 数据控制语言,定义对数据库、表、字段、用户的访问权限和安全级别,如:
-
GRANT、REVOKE等
-
Transaction Control:事务控制
-
COMMIT、ROLLBACK、SAVEPOINT等
-
-
1.4 SQL语句的书写规范
在数据库系统中,SQL语句不区分大小写(建议用大写) ,但字符串常量区分大小写
SQL语句可单行或多行书写,以“;”结尾。
关键词不能跨多行或简写。
用空格和缩进来提高语句的可读性。
子句通常位于独立行,便于编辑,提高可读性。
注释:
/* */ 和// 为多行注释
-- 和 # 为单行注释
2. 数据库操作
2.1 数据库的登录及退出
-
登录格式
mysql -u用户名 -h服务器的主机地址 -p密码 -A
分析
u 后面跟登录数据库的用户名,这里使用root
-h 后面的参数是服务器的主机地址,在这里客户端和服务器在同一台机器上,所以输入 localhost 或者 IP 地址
-p 后面是用户登录密码,注意:==-p 和密码之间没有空格。如果出现空格,系统将不会把后面的字符串当成密码来对待==,没有密码时不写
-A参数:不预读数据库信息,加上该参数则不预读数据库中的表等信息,不会有表名及列名的补全,但读取速度会加快,不加该参数可能使用数据库时出现下列提示(不影响使用)
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
-
显示信息解释:
-
Commands end with; or\g:mysql 命令是以分号(;)或“\g”来结束的,遇到这个结束符就开始执行命令
-
Your MySQL connection id is 22:数据库的连接次数
-
Server version: 8.0.37 Source distribution : 版本
-
Type 'help;' or '\h' for help:输入”help;“或者”\h“可以看到帮助信息
-
Type '\c' to clear the current input statement:表示遇到”\c“就清除前面的命令,注意不是清屏
-
-
退出:exit quit \q
PS C:\Users\Administrator> mysql -uroot -p
Enter password: ******
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 20
Server version: 8.0.37 MySQL Community Server - GPLCopyright (c) 2000, 2024, Oracle and/or its affiliates.Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql>\q# 注意:带有密码登录,会有警告,提示不安全
PS C:\Users\Administrator> mysql -uroot -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 21
Server version: 8.0.37 MySQL Community Server - GPLCopyright (c) 2000, 2024, Oracle and/or its affiliates.Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql>
2.2 查看数据库
- 格式
mysql> show databases [like 条件]; # 注意有s
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.00 sec)
- MySQL自带数据库
Information_schema: 主要存储了系统中的一些数据库对象信息,如:用户表信息、列信息、权限信息、字符集信息、分区信息等。(数据字典表)
performance_schema:主要存储数据库服务器的性能参数
mysql: 存储了系统的用户权限信息及帮助信息
sys: 5.7新增,之前版本需要手工导入。这个库是通过视图的形式把information_schema 和performance_schema结合起来,查询出更加令人容易理解的数据
- 使用条件查看
mysql> show databases like 'sys';
+----------------+
| Database (sys) |
+----------------+
| sys |
+----------------+
1 row in set (0.00 sec)
- 带有通配符的条件
%:匹配任意零个或多个字符
_ :匹配任意单个字符
mysql> show databases like 's%';
+---------------+
| Database (s%) |
+---------------+
| sys |
+---------------+
1 row in set (0.00 sec)
- 显示时间
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.3 创建数据库
-
格式
create database 数据库名
-
示例
mysql> create database testdb;
Query OK, 1 row affected (0.00 sec)mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| testdb |
+--------------------+
-
如数据库已存在,则报错
mysql> create database testdb;
ERROR 1007 (HY000): Can't create database 'testdb'; database exists
-
查看创建数据哭的语句
# 格式
show create database 数据库名
mysql> show create database testdb;
+----------+----------------------------------------------------------------------------------------------------------------------------------+
| Database | Create Database |
+----------+----------------------------------------------------------------------------------------------------------------------------------+
| testdb | CREATE DATABASE `testdb` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */ |
+----------+----------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)# 分析:
# 上述显示创建数据库语句的内容可看做3段内容# CREATE DATABASE `testdb` :表示创建数据库testdb# /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ :表示注释内容,显示字符集采用utf8mb4方案,一个字符需要 1 ~ 4 个字节。可以存储一些 emoji 表情; utf8mb4_0900_ai_ci表示字符比较规则即ai为不区分重音,ci为不区分大小写# /*!80016 DEFAULT ENCRYPTION='N' */ 表示数据库未加密
-
注意:再创建数据库或查看创建数据库语句时,database没有s
2.4 mysql中的反引号
上例中查看的sql语句有反引号,其作用可以避免一些与SQL语法冲突的问题,同时可以使代码更加规范化和易读性更强
如 select name, address from table; 其中table若当做表名但其为关键字回报错,加上反引号可以避免与SQL关键字的冲突:
mysql> select name, address from `table`;
-
注意:
只有保留关键字和特殊字符需要使用反引号,普通的表名和列名不需要
数据类型之间可以加或者不加反引号,但为了代码规范化,建议加上
2.5 切换数据库
查看当前使用的数据库,格式:
select database();
注意: 当前没有使用数据库,则显示空
mysql> select database();
+------------+
| database() |
+------------+
| NULL |
+------------+
选择数据库格式
use 数据库名
mysql> use testdb;
Database changed
mysql> select database(); # 再次查看
+------------+
| database() |
+------------+
| testdb |
+------------+
2.6 查看当前用户
mysql> select user();
+----------------+
| user() |
+----------------+
| root@localhost |
+----------------+
2.7 删除数据库
格式:
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.8 小结
# 新建数据库
create database 数据库名# 设为当前数据库
use 数据库名# 查看当前使用的数据库
select database();# 显示所有数据库
show databases;# 删除数据库
drop database 数据库名# 查看当前登录的用户及主机名
select user();
2.9 习题
-
创建temp1、temp2数据库,查看所有数据库,使用temp1数据库,删除所有数据库
见文章MySQL库表操作-数据库操作练习-CSDN博客
3. MySQL字符集
MySQL字符集包括字符集(CHARACTER)和排序规则(校对规则)(COLLATION)两个概念
3.1 字符集
-
Character Set(字符集):是字符的编码规则,规定了字符在数据库中的存储格式,比如占多少空间,支持哪些字符等
-
不同的字符集有不同的编码规则,在运维和使用MySQL数据库中,选取合适的字符集非常重要,如果选择不恰当,轻则影响数据库性能,严重的可能导致数据存储乱码
-
mysql 5.7的默认字符集是latin1,而8.0中是utf8mb4;
-
mysql8的库表创建以及程序中尽可能使用utf8mb4字符集(可支持emoji)
-
mysql中的utf8字符集是utf8mb3字符集的别名,避免使用
latin1支持西欧字符、希腊字符等gbk支持中文简体字符,但是不是国际通用字符集big5支持中文繁体字符utf8几乎支持世界所有国家的字符。utf8mb4完全兼容UTF-8,用四个字节存储更多的字符
3.2 字符序
字符序就是字符排序的规则集合
如:使用A>B>a>b的规则来进行排序或者另一种规则a>b>A>B顺序排序
字符序主要对字符的排序有影响
3.3 查看MySQL字符集
- 查看所有支持的字符集
# 格式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:该字符集中字符最大存储长度。# 或者使用\g替代定界符分号
mysql> show character set\g
# 格式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> 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 |
+---------+------------------+--------------------+--------+
3.4 查看MySQL字符序
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";
3.5 查看 当前字符集的设置
-
通过变量查看
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/ |
+--------------------------+----------------------------+
-
变量含义
character_set_client:MySQL客户端的字符集。
character_set_connection:数据通信链路字符集,当MySQL客户机向服务器发送请求时,请求数据以该字符集进行编码。
character_set_database:数据库默认使用的字符集。
character_set_filesystem:MySQL服务器文件系统字符集,该值是固定的binary。
character_set_results:服务器返回给客户端的结果使用的字符集。
character_set_server:服务器默认的字符集。
character_set_system:服务器存储元数据使用的字符集。
3.6 utf8和utf8mb4的区别
MySQL在5.5.3之后增加了这个utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode。好在utf8mb4是utf8的超集,除了将编码改为utf8mb4外不需要做其他转换。当然,为了节省空间,一般情况下使用utf8也就够了。
既然utf8能够存下大部分中文汉字,那为什么还要使用utf8mb4呢? 原来mysql支持的 utf8 编码最大字符长度为 3 字节,如果遇到 4 字节的宽字符就会插入异常了。三个字节的 UTF-8 最大能编码的 Unicode 字符是 0xffff,也就是 Unicode 中的基本多文种平面(BMP)。也就是说,任何不在基本多文本平面的 Unicode字符,都无法使用 Mysql 的 utf8 字符集存储。包括 Emoji 表情(Emoji 是一种特殊的 Unicode 编码,常见于 ios 和 android 手机上),和很多不常用的汉字,以及任何新增的 Unicode 字符,如表情等等(utf8的缺点)。
因此在8.0之后,建议大家使用utf8mb4这种编码。
4. 数据库对象
4.1 组成
4.2 数据库对象的命名规则
命名使用具有意义的英文词汇,词汇中间以下划线分隔
名称由字母、数字、#、下划线、$组成,必须以英文字母开头
不要使用MySQL的保留字
所有数据库对象使用小写字母,实际上MySQL中是可以设置大小写是否敏感的,为了保证统一性应使用小写表示
在同一个数据库对象集合内对象不能同名
4.3 生产中对象命名规范
数据库:
数据库命名尽量不超过30个字符
数据库命名一般为项目名称+代表库含义的简写,比如IM项目的工作流数据库,可以是 im_flow
命名应使用小写
表:
常规表:以t_开头,t代表table的意思,命名规则即 t + 模块(包含模块含义的简写)+ 表(包含表含义的简写),比如用户模块的教育信息表:t_user_eduinfo
临时表:temp前缀+模块+表+日期后缀:temp_user_eduinfo_20240520
备份表(用于保存和归档历史数据或者作为灾备恢复的数据)命名规则,bak前缀+模块+表+日期后缀:bak_user_eduinfo_20231219
同一个模块的表尽可能使用相同的前缀,表名称尽可能表达含义
多个单词以下划线 _ 分隔
常规表表名尽量不超过30个字符,temp表和bak表视情况而定,也尽量简短为宜,命名应使用小写
5. 表的基本操作
5.1 数据类型
-
类型组成:数字、文本、日期/时间类型
-
整型
数据类型 | 字节数 | 带符号值范围 | 不带符号值范围 |
---|---|---|---|
tinyint | 1 | [-128,[127] | [0,255] |
smallint | 2 | [-32768,32767] | [0,65535] |
mediumint | 3 | [-8388608,8388607] | [0,16777215] |
int | 4 | [-2147483648,2147483647] | [0,4294967295] |
bigint | 8 | [-9223372036854775808,9223372036854775807] | [0,18446744073709551616] |
- 注意:
实际开发的角度,一定要为合适的列选取合适的数据类型,如
- 一个枚举字段只有0和1两个枚举值,选用TINYINT就足够了,但在开发场景下却使用了BIGINT,这就造成了资源浪费
- 简单计算一下,假使该数据表中有100W数据,那么总共浪费了700W字节也就是6.7M左右,如果更多的表这么做了,那么浪费的更多
- 整型(N)表现形式:有时代码写法为int(10),表示数字宽度限制,要求如下:
- 无论N等于多少,int永远占4个字节
- N表示的是显示宽度,不足则补0,超过长度则会无视长度直接显示整个数字
浮点型
数据类型 | 字节数 | 备注 |
---|---|---|
float | 4 | 单精度浮点型 |
double | 8 | 双精度浮点型 |
注意:可以使用float(M,D)、double(M,D)格式限制宽度按(M)和精度(D),如float(3,2),不指定M、D的时,会按照实际的精度来处理
定点型:decimal(size,d) ,作为字符串存储的 DOUBLE 类型,允许固定的小数点,由于float、double类型存在精度丢失问题,即**写入数据库的数据未必是插入数据库的数据**,而decimal无论写入数据中的数据是多少,都不会存在精度丢失问题,这就是要引入decimal类型的原因,decimal类型常见于银行系统、互联网金融系统等对小数点后的数字比较敏感的系统中,结论:float/double在db中存储的是近似值,而decimal则是以字符串形式进行保存。
mysql> create database mydb1_test;mysql> use mydb1_test;
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.03 sec)mysql> insert into t1 value (1234567.66,1234567899000000.66,123456789000000.66);
Query OK, 1 row affected (0.00 sec)mysql> select * from t1;
+------------+---------------------+--------------------+
| float_num | double_num | decimal_num |
+------------+---------------------+--------------------+
| 1234567.62 | 1234567899000000.80 | 123456789000000.66 |
+------------+---------------------+--------------------+
# 注意:Query OK, 0 rows affected, 2 warnings (0.03 sec)含义如下:该信息是MySQL数据库执行SQL语句的结果。它表示SQL语句成功执行,但是没有影响到任何行,并且出现了两个警告。"Query OK" 表示查询操作成功。"0 rows affected" 表示SQL语句执行后,影响到数据库中的0行数据。"2 warnings" 表示在执行这个查询时,发出了两个警告。"(0.03 sec)" 表示查询执行的时间。
可以通过命令 show warnings; 查看警告信息
-
文本型
数据类型 | 描述 |
---|---|
char(size) | 保存固定长度的字符串(可包含字母、数字以及特殊字 符)。在括号中指定字符串的长度。最多 255 个字符。 |
varchar(size) | 保存可变长度的字符串(可包含字母、数字以及特殊字 符)。在括号中指定字符串的最大长度。最多 255 个字 符。 注释:如果值的长度大于 255,则被转换为 TEXT 类型。 |
tinytext | 存放最大长度为 255 个字符的字符串。 |
text | 存放最大长度为 65,535 个字符的字符串。 |
blob | 用于 BLOBs (Binary Large OBjects)。存放最多 65,535 字节的数据。 |
mediumtext | 存放最大长度为 16,777,215 个字符的字符串。 |
mediumelob | 用于 BLOBs (Binary Large OBjects)。存放最多 16,777,215 字节的数据。 |
longtext | 存放最大长度为 4,294,967,295 个字符的字符串。 |
longblob | 用于 BLOBs (Binary Large OBjects)。存放最多 4,294,967,295 字节的数据。 |
enum(x,y,z,etc.) | 允许输入可能值的列表。可以在 ENUM 列表中列出最大 65535 个值。如果列表中不存在插入的值,则插入空值。 注释:这些值是按照你输入的顺序存储的。 可以按照此格式输入可能的值: ENUM('X','Y','Z') |
set | 与 enum 类似, SET 最多只能包含 64 个列表项,不过 SET 可存储一个以上的值。 |
- 文本型
数据类型 | 描述 |
---|---|
char(size) | 保存固定长度的字符串(可包含字母、数字以及特殊字 符)。在括号中指定字符串的长度。最多 255 个字符。 |
varchar(size) | 保存可变长度的字符串(可包含字母、数字以及特殊字 符)。在括号中指定字符串的最大长度。最多 255 个字 符。 注释:如果值的长度大于 255,则被转换为 TEXT 类型。 |
tinytext | 存放最大长度为 255 个字符的字符串。 |
text | 存放最大长度为 65,535 个字符的字符串。 |
blob | 用于 BLOBs (Binary Large OBjects)。存放最多 65,535 字节的数据。 |
mediumtext | 存放最大长度为 16,777,215 个字符的字符串。 |
mediumelob | 用于 BLOBs (Binary Large OBjects)。存放最多 16,777,215 字节的数据。 |
longtext | 存放最大长度为 4,294,967,295 个字符的字符串。 |
longblob | 用于 BLOBs (Binary Large OBjects)。存放最多 4,294,967,295 字节的数据。 |
enum(x,y,z,etc.) | 允许输入可能值的列表。可以在 ENUM 列表中列出最大 65535 个值。如果列表中不存在插入的值,则插入空值。 注释:这些值是按照你输入的顺序存储的。 可以按照此格式输入可能的值: ENUM('X','Y','Z') |
set | 与 enum 类似, SET 最多只能包含 64 个列表项,不过 SET 可存储一个以上的值。 |
注意:
- blob和text都是为了存储很大数据而设计的字符串数据类型,blob采用二进制形式存储无排序规则和字符集,text采用字符形式存储且有排序规则和字符集适用于存储如文章内容、评论等
- char是固定长度字符串,其长度范围为0~255且与编码方式无关,无论字符实际长度是多少,都会按照指定长度存储,不够的用空格补足,char类型数据时会将结尾的所有空格处理掉
mysql> create table t2(char_value char(5) , varchar_value varchar(5));
Query OK, 0 rows affected (0.01 sec)mysql> insert into t2 value('a','a');
Query OK, 1 row affected (0.00 sec)mysql> insert into t2 value(' a',' a');
Query OK, 1 row affected (0.01 sec)mysql> insert into t2 value('a ','a ');
Query OK, 1 row affected (0.00 sec)mysql> insert into t2 value(' a ',' a ');
Query OK, 1 row affected (0.00 sec)mysql> select * from t2;
+------------+---------------+
| char_value | varchar_value |
+------------+---------------+
| a | a |
| a | a |
| a | a |
| a | a |
+------------+---------------+
4 rows in set (0.00 sec)mysql> select length(char_value),length(varchar_value) from t2;
+--------------------+-----------------------+
| length(char_value) | length(varchar_value) |
+--------------------+-----------------------+
| 1 | 1 |
| 3 | 3 |
| 1 | 3 |
| 3 | 5 |
+--------------------+-----------------------+
4 rows in set (0.00 sec)
-
date 类型
数据类型 | 字节数 | 格式 | 备注 |
---|---|---|---|
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 | 存储日期+时间,可作时间戳 |
mysql> create table t3( date_value date,time_value time,year_value year,datetime_value datetime,timestamp_value timestamp);
Query OK, 0 rows affected (0.02 sec)mysql> insert into t3 values(now(), now(), now(), now(), now());
Query OK, 1 row affected, 1 warning (0.01 sec)mysql> select * from t3;
- 总结:常用数据类型:
5.2 创建表
- 格式:
create table 表名 (表选项)
- 表定义选项格式为:
列名1 列类型1 约束, 列名2 列类型2 约束,……
- 默认的情况是,表被创建到当前的数据库中。若表已存在、没有当前数据库或者数据库不存在,则会出现错误
- 使用 crate table 创建表时,必须指定以下信息:
要创建的表的名称不区分大小写,不能使用SQL语言中的关键字,如DROP、ALTER、INSERT等。
必须指定数据表中每个列(字段)的名称和数据类型,如果创建多个列,要用逗号隔开
-
示例1:创建数据库并新建表
数据表属于数据库,在创建数据表之前,应使用语句“use <数据库>”指定操作在哪个数据库中进行,如果没有选择数据库,就会抛出 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 student1(id int, name varchar(30), sex char(2), age int unsigned, score float, addr varchar(50));
Query OK, 0 rows affected (0.02 sec)mysql> show tables;
+-------------------------+
| Tables_in_mydb2_stuinfo |
+-------------------------+
| student1 |
+-------------------------+
示例2:新建员工表
mysql> create database mydb3_employee;
Query OK, 1 row affected (0.01 sec)mysql> use mydb3_employee;
Database changedmysql> create table tb1(id int(11), name varchar(25), salary float);
Query OK, 0 rows affected, 1 warning (0.03 sec)mysql> show tables;
+--------------------------+
| Tables_in_mydb3_employee |
+--------------------------+
| tb1 |
+--------------------------+
1 row in set (0.00 sec)
练习:
在mydb2_stuinfo库中新建班级表class1,字段如下:cla_num int(5) , cla_name varchar(10) , number int(4) , monitor varchar(20) ,creation_date date
mysql> use mydb2_stuinfo;mysql> create table class1(cla_num int(5), cla_name varchar(10), number int(4),monitor varchar(20),creation_date date);mysql> desc class1;
+---------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| cla_num | int | YES | | NULL | |
| cla_name | varchar(10) | YES | | NULL | |
| number | int | YES | | NULL | |
| monitor | varchar(20) | YES | | NULL | |
| creation_date | date | YES | | NULL | |
+---------------+-------------+------+-----+---------+-------+
5 rows in set (0.00 sec)
5.3 查看表
show语句:显示当前数据库中已有的数据表
describe语句:查看数据表中各列的信息
-
字段意义分析:
-
Field :字段名称
-
type:字段类型
-
null:是否允许为空
-
key:索引类型
-
default:默认值
-
extra:填充
-
-
使用\G可以查看更全面的表定义信息
mysql> show create table student1\G
*************************** 1. row ***************************Table: student1
Create Table: CREATE TABLE `student1` (`id` int DEFAULT NULL,`name` varchar(30) DEFAULT NULL,`sex` char(2) DEFAULT NULL,`age` int unsigned DEFAULT NULL,`score` float DEFAULT NULL,`addr` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
5.4 删除表
格式
drop table [if exists] 表名;
mysql> use mydb3_employee;
Database changedmysql> show columns from tb1;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(25) | YES | | NULL | |
| salary | float | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)mysql> drop table tb1;
Query OK, 0 rows affected (0.01 sec)mysql> show tables;
Empty set (0.00 sec)
注意:
-
用户必须拥有执行 drop table 命令的权限,否则数据表不会被删除
-
推荐使用if exists字句,即先判断是否存在,存在则删除,如:
mysql> drop table if exists tb1;
Query OK, 0 rows affected (0.01 sec)
5.5 修改表
# 法1:
alter table 表名 rename 新表名; # 法2:
rename table 表名 to 新表名;
mysql> use mydb2_stuinfo;
Database changed
mysql> show tables;
+-------------------------+
| Tables_in_mydb2_stuinfo |
+-------------------------+
| class1 |
| student1 |
+-------------------------+
1 row in set (0.00 sec)mysql> create table student2(id int(11), name varchar(30), salary float);
Query OK, 0 rows affected, 1 warning (0.05 sec)mysql> desc student2;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(30) | YES | | NULL | |
| salary | float | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
3 rows in set (0.01 sec)mysql> alter table student2 rename student3; # 修改
Query OK, 0 rows affected (0.01 sec)mysql> show tables;
+-------------------------+
| Tables_in_mydb2_stuinfo |
+-------------------------+
| class1 |
| student1 |
| student3 |
+-------------------------+
2 rows in set (0.01 sec)mysql> rename table student3 to teacher1; # 修改
Query OK, 0 rows affected (0.01 sec)mysql> show tables;
+-------------------------+
| Tables_in_mydb2_stuinfo |
+-------------------------+
| class1 |
| student1 |
| teacher1 |
+-------------------------+
2 rows in set (0.00 sec)
- 添加新列
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: 2: 表示成功导入或处理的记录总数是2条。Duplicates: 0: 表示在操作过程中没有发现重复的记录。Warnings: 0: 表示在操作过程中没有产生任何警告。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 | |
| password | char(8) | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
7 rows in set (0.00 sec)# 例:再添加一个新列notes varchar(30),位置在score之前
mysql> alter table student1 add notes varchar(30) after age;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> 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 | |
| notes | varchar(30) | YES | | NULL | |
| score | float | YES | | NULL | |
| addr | varchar(50) | YES | | NULL | |
| password | char(8) | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+# 例:再第一列添加一个新列
mysql> alter table student1 add aa int first;mysql> desc student1;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| aa | int | YES | | NULL | |
| id | int | YES | | NULL | |
| name | varchar(30) | YES | | NULL | |
| sex | char(2) | YES | | NULL | |
| age | int unsigned | YES | | NULL | |
| notes | varchar(30) | YES | | NULL | |
| score | float | YES | | NULL | |
| addr | varchar(50) | YES | | NULL | |
| password | char(8) | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
9 rows in set (0.00 sec)
- 删除列
alter table 表名 DROP 列名;
# 例:删除上例的notes、aa列
mysql> alter table student1 drop notes;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> alter table student1 drop aa;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> 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 | |
| password | char(8) | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
- 修改列名
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: 0mysql> 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 | |
| passwd | char(8) | YES | | NULL | |
+--------+--------------+------+-----+---------+-------+
7 rows in set (0.01 sec)
- 修改列类型
alter table 表名 modify 列名 列类型;
# 插入新列,修改类型
mysql> alter table student1 add birthday char(10); # 增加
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> 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 | |
| passwd | char(8) | YES | | NULL | |
| birthday | char(10) | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
8 rows in set (0.00 sec)mysql> alter table student1 modify birthday date; # 修改
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> 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 | |
| passwd | char(8) | YES | | NULL | |
| birthday | date | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
8 rows in set (0.00 sec)
5.6 修改列位置
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;
5.7 练习
新建商品数据库mydb4_product,
使用该数据库
创建商品表pro_tb1,字段包含编号 num int(4),商品名trade_name varchar(30),数量number int(4) ,单价price float(5,2)
显示创建表的字段内容
新增一列备注notes varchar(30)
将编号num字段类型修改为char(4)
删除该表(先判断)
mysql> create database mydb4_product;
Query OK, 1 row affected (0.00 sec)mysql> use mydb4_product;
Database changedmysql> create table pro_tb1(num int(4), trade_name varchar(30), number int(4), price float(5,2));
Query OK, 0 rows affected, 3 warnings (0.03 sec)mysql> desc pro_tb1;mysql> alter table pro_tb1 add notes varchar(30);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> desc pro_tb1;mysql> alter table pro_tb1 modify num char(4);
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> desc pro_tb1;mysql> drop table if exists pro_tb1;
Query OK, 0 rows affected (0.01 sec)mysql> show tables;
Empty set (0.00 sec)
5.8 复制表的结构
-
方法一:在create table语句的末尾添加like子句,可以将源表的表结构复制到新表中,语法格式如下:
create table 新表名 like 源表
mysql> use mydb2_stuinfo;mysql> insert into student1 value(1000,"zhangsan","M",18,98.5,"xi'an","12345678","2005-10-01");
Query OK, 1 row affected (0.00 sec)mysql> insert into student1 value(1001, "lisi", "W", 20,66.79, "baoji","87654321","2003-5-01");mysql> select * from student1;mysql> create table student2 like student1;
Query OK, 0 rows affected (0.01 sec)mysql> show tables;
+-------------------------+
| Tables_in_mydb2_stuinfo |
+-------------------------+
| class1 |
| student1 |
| teacher1 |
+-------------------------+
3 rows in set (0.00 sec)mysql> select * from student2; # 注意:只是复制结构框架
Empty set (0.00 sec)
- 方法二:在create table语句的末尾添加一个select语句,可以实现表结构的复制,甚至可以将源表的表记录拷贝到新表中,下面的语法格式将源表的结构和记录都拷贝到新表中。
create table 新表名 select * from 源表
mysql> create table student3 select * from student1;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> show tables;
+-------------------------+
| Tables_in_mydb2_stuinfo |
+-------------------------+
| class1 |
| student1 |
| student2 |
| student3 |
| teacher1 |
+-------------------------+
4 rows in set (0.00 sec)mysql> select * from student3;
-
方法三:如果已经存在一张结构一致的表,复制数据:
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: 0mysql> select * from student2;mysql> drop table if exists student2;
mysql> drop table if exists student3;
mysql> drop table if exists teacher1;
5.9 数据库字典
数据字典:类似于系统编目或花名册,它保存数据库服务器上的元数据信息(数据库的整体属性信息)
元数据(meta data):即“data about data” 关于数据的数据,理解为描述数据的数据,内容包括:数据库的属性信息、数据表的属性信息、字段的属性信息、视图的属性信息、用户信息、统计类信息等。
information_schema数据库是MySQL系统自带的数据库,它提供了数据库元数据的访问方式
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mydb1_test |
| mydb2_stuinfo |
| mydb3_employee |
| mydb4_product |
| mysql |
| performance_schema |
| sys |
+--------------------+
8 rows in set (0.00 sec)
-
information_schema就像是MySQL实例的一个百科全书,记录了数据库当中大部分我们需要了结的信息,比如字符集,权限相关,数据库实体对象信息,外检约束,分区,压缩表,表信息,索引信息,参数,优化,锁和事物等等。
-
通过information_schema我们可以窥透整个MySQL实例的运行情况,可以了结MySQL实例的基本信息,甚至优化调优,维护数据库等,可以说是真正的一部百科全书。
mysql> use information_schema ;mysql> show tables;# 常用表解释
tables-存放数据库里所有的数据表、以及每个表所在数据库。
schemata-存放数据库里所有的数据库信息
views-存放数据库里所有的视图信息。
columns-存放数据库里所有的列信息。
triggers-存放数据库里所有的触发器。
routines-存放数据库里所有存储过程和函数。
key_column_usage-存放数据库所有的主外键
table_constraints-存放数据库全部约束。
statistics-存放了数据表的索引。
……
5.10 小结
# 新建表
create tables 表名(列名1 类型 , 列名2 类型 ……);# 查看表结构
desc 表名;# 修改表名
alter table 旧表名 rename 新表名;# 表中添加新列
alter table 表名 add 新列名 列类型 [after|first] 列名; (after为之后)# 删除列
alter table 表名 DROP 列名;# 修改列名
alter table 表名 change 旧列名 新列名 列类型;# 修改列类型
alter table 表名 modify 列名 列类型;# 移动列
alter table 表名 modify 列名 列类型 after 某列;# 删除表
drop table if exists 表名;
5.11 删除的注意事项
1.删除数据库表之前,一定要备份数据,以免数据丢失。
2.在删除数据库表之前,要确保该表没有被其他的表所引用,否则可能会破坏外键约束。
3.在删除数据库表之前,要确保该表的数据已经备份,并且不再需要使用。
4.在删除数据库表之前,要确保该表的数据已经被清空,否则会破坏外键约束。
5.在删除数据库表之前,要确保该表的所有索引都已经被删除。如果还存在索引,可能会导致删除失败。
6.在删除数据库表之前,要确保该表的所有相关程序已经停止运行,以免影响其他程序的正常运行。
6. 表的约束
6.1 概念
-
为什么需要约束
-
真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性,如:有一个字段是身份证,要求是唯一的
-
定义字段的类型无法满足对表的约束:
-
表字段是否可以为NULL,有没有默认值,表字段的解释能不能加上
-
对于数字类型的字段可不可以指定默认表示的位数,可不可以将这个字段设置称为唯一标识该行的数据
-
-
本质上Mysql是一套数据存储解决方案,除了解决基本的数据存储功能之外,还要保证数据尽可能的安全,减少用户的误操作可能性, 约束的体现,不仅仅可以体现在数据库层面,在我们进行用户业务逻辑编码的时候,我们其实也可以做判断(约束),约束其实不仅仅只能出现在数据库层而上,编码层面也是可以体现
-
-
约束是什么:约束是在==表上强制执行的数据校验规则==,本质上是Mysql通过限制用户操作的方式,来达到维护数据本身安全及数据完整性的一套方案
-
数据的完整性要从以下四个方面考虑:
-
实体完整性(Entity Integrity):例如,同一个表中,不能存在两条完全相同无法区分的记录
-
域完整性(Domain Integrity):例如:年龄范围0-120,性别范围“男/女”
-
引用完整性(Referential Integrity):例如:员工所在部门,在部门表中要能找到这个部门
-
用户自定义完整性(User-defined Integrity):例如:用户名唯一、密码不能为空等,本部门经理的工资不得高于本部门职工的平均工资的5倍。
-
-
约束作为数据库对象,存放在系统表中,也有自己的名字
-
常见约束:
-
非空约束
-
默认值约束
-
主键约束
-
外键约束
-
唯一约束
-
检查约束
-
-
创建约束的时机:
-
在建表的同时创建
-
建表后创建(修改表)
-
-
约束可定义列级或表级约束
6.2 语法
-
列级约束:在定义列的同时定义约束
create table 表名 (列名 类型 约束 )
-
表级约束:在定义了所有列之后定义的约束
create table 表名 constraint 约束名 约束类型 (列信息)
-
创建表之后添加约束:
alter table 表名 add constraint 约束名 约束类型(要约束的列名)
6.3 非空约束
作用:限定某个字段/某列的值不允许为空
两个值:null(默认的)和not null(不为空)
列字段默认一般都是空,但是实际开发时,尽可能保证字段不为空,因为数据为空没办法参与运算
所有数据类型的值都可以是NULL,空字符串不等于NULL,0也不等于NULL示例:
mysql> use mydb2_stuinfo;
Database changedmysql> 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 | |
| passwd | char(8) | YES | | NULL | |
| birthday | date | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
8 rows in set (0.00 sec)# 插入数据
mysql> insert into student1(id,name) values('1002','张三');
Query OK, 1 row affected (0.00 sec)mysql> insert into student1(id,name) values('1003','李四');
Query OK, 1 row affected (0.00 sec)mysql> select * from student1;
+------+----------+------+------+-------+-------+----------+------------+
| id | name | sex | age | score | addr | password | birthday |
+------+----------+------+------+-------+-------+----------+------------+
| 1000 | zhangsan | M | 18 | 98.50 | xi'an | 12345678 | 2005-10-01 |
| 1001 | lisi | w | 20 | 66.79 | baoji | 87654321 | 2003-05-01 |
| 1002 | 张三 | NULL | NULL | NULL | NULL | NULL | NULL |
| 1003 | 李四 | NULL | NULL | NULL | NULL | NULL | NULL |
+------+----------+------+------+-------+-------+----------+------------+
4 rows in set (0.00 sec)# 显示sex之后的列都为NULL,表示内容没有填
-
若需要某些字段必须写入,应该怎么处理,如:创建一个班级表,包含班级名和班级所在的教室,站在正常的业务逻辑中:如果班级没有名字,你不知道你在哪个班级,如果教室名字可以为空,就不知道在哪上课,所以我们在设计数据库表的时候,一定要在表中进行限制,满足上面条件的数据就不能插入到表中,这就是“约束”
mysql> create table myclass1(class_name varchar(20) not null, class_room varchar(20) not null, class_id int); # 无约束
Query OK, 0 rows affected (0.02 sec)mysql> desc myclass1;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| class_name | varchar(20) | NO | | NULL | |
| class_room | varchar(20) | NO | | NULL | |
| class_id | int | YES | | NULL | |
+------------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)# 插入数据时:
mysql> insert into myclass1 (class_room) values('计科1');
ERROR 1364 (HY000): Field 'class_name' doesn't have a default value # 失败,因为name有约束不能为空mysql> insert into myclass1 (class_name,class_room) values('A104','计科1'); # 同时插入成功
Query OK, 1 row affected (0.00 sec)mysql> select * from myclass1;
+------------+------------+----------+
| class_name | class_room | class_id |
+------------+------------+----------+
| A104 | 计科1 | NULL |
+------------+------------+----------+
1 row in set (0.00 sec)
# id字段无约束,可以为空
- 以上为创建表时的设置,也可以创建之后修改:
# 语法:
alter table <数据表名> change column <字段名> <字段名> <数据类型> not null;
mysql> alter table student1 change column id id int not null;
# 也可以通过modify修改
mysql> alter table student1 modify name varchar(30) not null;# modify字句中省略not null 相当于设置为可以为空
mysql> desc student1;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id | int | NO | | NULL | |
| name | varchar(30) | NO | | NULL | |
| sex | char(2) | YES | | NULL | |
| age | int unsigned | YES | | NULL | |
| score | float | YES | | NULL | |
| addr | varchar(50) | YES | | NULL | |
| passwd | char(8) | YES | | NULL | |
| birthday | date | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
8 rows in set (0.00 sec)
-
删除 not null
mysql> alter table student1 modify id int null;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
# 或者
mysql> alter table student1 modify name varchar(30);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 | |
| passwd | char(8) | YES | | NULL | |
| birthday | date | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
8 rows in set (0.00 sec)
6.4 默认值约束
-
作用:给某个字段/某列指定默认值,一旦设置默认值,在插入数据时,如果此字段没有显式赋值,则赋值为默认值。
mysql> create table teacher1(id int not null, name varchar(30) not null, sex char(2) default '女');
Query OK, 0 rows affected (0.03 sec)mysql> desc teacher1;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | | NULL | |
| name | varchar(30) | NO | | NULL | |
| sex | char(2) | YES | | 女 | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.01 sec)mysql> insert into teacher1(id,name) values(1001,'林雪');
Query OK, 1 row affected (0.00 sec)mysql> select * from teacher1;
+------+--------+------+
| id | name | sex |
+------+--------+------+
| 1001 | 林雪 | 女 |
+------+--------+------+
1 row in set (0.00 sec)mysql> insert into teacher1(id,name,sex) values(1002,'石磊','男'); # 也可以全字段插入
Query OK, 1 row affected (0.01 sec)mysql> select * from teacher1;
+------+--------+------+
| id | name | sex |
+------+--------+------+
| 1001 | 林雪 | 女 |
| 1002 | 石磊 | 男 |
+------+--------+------+
2 rows in set (0.00 sec)
# 创建表之后增加默认值:
mysql> alter table student1 modify sex char(2) default '女';
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> desc student1;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(30) | YES | | NULL | |
| sex | char(2) | YES | | 女 | |
| age | int unsigned | YES | | NULL | |
| score | float | YES | | NULL | |
| addr | varchar(50) | YES | | NULL | |
| passwd | char(8) | YES | | NULL | |
| birthday | date | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
8 rows in set (0.00 sec)mysql> insert into student1 (id,name) values(1004,'王五');
Query OK, 1 row affected (0.01 sec)mysql> select * from student1;
-
默认值的生效:数据在插入的时候不给该字段赋值,就使用默认值
-
注意:若某字段都设置了not null和default约束,则按照不插入时会选择默认值,插入时选择插入值,所以此时not null毫无意义
mysql> alter table teacher1 add age int not null default 18;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> desc teacher1;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | | NULL | |
| name | varchar(30) | NO | | NULL | |
| sex | char(2) | YES | | 女 | |
| age | int | NO | | 18 | |
+-------+-------------+------+-----+---------+-------+
4 rows in set (0.01 sec)# not null和defalut一般不需要同时出现,因为default本身有默认值,不会为空
6.5 列描述--comment
列描述没有实际含义,专门用来描述字段,会根据表创建语句保存,供操作者来查看该列的含义,相当于C/C++的注释
mysql> create table myclass2( class_name varchar(20) not null comment '教室',class_room varchar(20) default '计科2');
Query OK, 0 rows affected (0.02 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.00 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' COMMENT '班级'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
6.6 主键约束
作用:数据库存储数据不是唯一的目的,还要考虑到提取数据,一般要求数据库表中的记录要有一个特定的唯一标识,来表示唯一性,这个唯一的特定标识就是主键,类似于序号学号这样的唯一标识,可以根据主键来唯一地筛选出一条记录
主键: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(20) | NO | | NULL | |
| sex | char(2) | YES | | 男 | |
+-------+--------------+------+-----+---------+-------+
3 rows in set (0.01 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 rows 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(30) | NO | | NULL | |
| sex | char(2) | YES | | 女 | |
| age | int | NO | | 18 | |
+-------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
-
注意:如果该字段内有重复值,则不能以该字段新增为主键,必须先把重复的数据去掉然后才能添加该列为主键
-
删除主键
alter table 表名 drop primary key;
mysql> alter table teacher1 drop primary key;
Query OK, 2 rows affected (0.04 sec)
Records: 2 Duplicates: 0 Warnings: 0mysql> desc teacher1;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | | NULL | |
| name | varchar(30) | NO | | NULL | |
| sex | char(2) | YES | | 女 | |
| age | int | NO | | 18 | |
+-------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
-
复合主键:在创建表的时候,在所有字段之后,使用primary key(主键字段列表)来创建主键,如果有多个字段作为主键,可以使用复合主键,这些字段合在一起是一个主键,也就是让多个字段联合在一起作为唯一标识,单个字段主键重复是没有问题的,只要不是成为复合主键的字段一起冲突就行
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.02 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 | |
| port | int unsigned | NO | PRI | NULL | |
+----------+--------------+------+-----+---------+-------+
4 rows in set (0.00 sec)mysql> insert into t2 values(1,'node1','192,168,48,2',120);
Query OK, 1 row affected (0.00 sec)mysql> select * from t2;
+------+----------+--------------+------+
| id | hostname | ip | port |
+------+----------+--------------+------+
| 1 | node1 | 192,168,48,2 | 120 |
+------+----------+--------------+------+
1 row in set (0.00 sec)mysql> insert into t2 values(2,'node2','192,168,48,3',120);
Query OK, 1 row affected (0.00 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' # 复合主键一起冲突,报错
6.7 主键自增长
-
作用:给主键添加自增长的数值
-
auto_increment:当对应的字段,不给值,会自动的被系统触发,系统会从当前字段中已经有的最大值+1操作,得到一个新的不同的值。通常和主键搭配使用,作为逻辑主键
-
注意:
-
自增长字段必须是==整数==,自增长字段可以不设置初始值,默认从1开始递增.
-
被自增长的字段必须作为主键或者其他具有唯一性的键使用,(必须保证这一列字段具有唯一性的字段)
-
自增长字段也可以插入数据,只要不与已有数据重复即可,之后新增数据会从最大值开始递增.
-
任何一个字段要做自增长,前提是本身是一个索引(key一栏有值).
-
一张表当中最多只能有一个自增长的列
-
约束的字段必须具备 NOT NULL 属性
-
-
示例:
# 先增加主键
mysql> use mydb2_stuinfo;
Database changedmysql> alter table student1 modify id int primary key;
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0# 设置自增长
mysql> alter table student1 modify id int auto_increment;
Query OK, 3 rows affected (0.05 sec)
Records: 3 Duplicates: 0 Warnings: 0# 查看
mysql> desc student1;
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(30) | YES | | NULL | |
| sex | char(2) | YES | | 女 | |
| age | int unsigned | YES | | NULL | |
| score | float | YES | | NULL | |
| addr | varchar(50) | YES | | NULL | |
| passwd | char(8) | YES | | NULL | |
| birthday | date | YES | | NULL | |
+----------+--------------+------+-----+---------+----------------+
8 rows in set (0.00 sec)mysql> insert into student1(name) values('关六');
Query OK, 1 row affected (0.00 sec)mysql> select * from student1;# 发现自动增长
- 指定自增长的起始值:如果第一条记录设置了该字段的初始值,那么新增加的记录就从这个初始值开始自增。例如,如果表中插入的第一条记录的 id 值设置为 5,那么再插入记录时,id 值就会从 5 开始往上增加
# 指定自增长的起始值为100
mysql> create table t3 ( id int primary key auto_increment, systemname varchar(10) not null )auto_increment=100;
Query OK, 0 rows affected (0.02 sec)# 插入一条记录
mysql> insert into t3(systemname) values('Linux');
Query OK, 1 row affected (0.00 sec)# 插入一条记录
mysql> insert into t3(systemname) values('windows');
Query OK, 1 row affected (0.00 sec)mysql> select * from t3;
+-----+------------+
| id | systemname |
+-----+------------+
| 100 | Linux |
| 101 | windows |
+-----+------------+
2 rows in set (0.01 sec)
6.8 唯一性约束
-
产生原因:一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键,唯一键就可以解决表中有多个字段需要唯一性约束的问题
-
作用:限制某个字段/某列的值不能重复
-
唯一键和主键的关系:
-
主键更多的是标识唯一性
-
唯一键更多的是保证在业务上,不要和别的信息出现重复
-
主键只能有一个,唯一键能设置多个
-
主键和唯一键不是对立关系而是补充关系,目的是让数据库创建出一个表具有非常强的约束,彻底杜绝用户的误插入,在一张表当中,可以有一个主键,也可以同时具有唯一键, 它们不是用来对比的,只是负责数据在不同层面的唯一性,既要保证选择成为主键的属性字段不能重复不能为空,同时也要保证本身具有唯一性的列的字段不能出现冲突
-
主键用来查找,唯一键用来保证数据的完整性
-
如:学生信息中有身份证号和学号两个字段,可以把身份证号设置成为主键,而所有学生的学号也不能重复,此时就可以把学号设置成唯一键
-
-
示例:创建表时实现
mysql> create table t4( id int primary key, name varchar(20) unique comment '名子不能重名,可以为空' );
Query OK, 0 rows affected (0.02 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.00 sec)# 插入数据
mysql> insert into t4 values(1,'刘文');
Query OK, 1 row affected (0.00 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.00 sec)mysql> select * from t4;
+----+--------+
| id | name |
+----+--------+
| 1 | 刘文 |
| 2 | 张磊 |
+----+--------+
2 rows in set (0.00 sec)
- 唯一键冲突,自增涨字段值不连续
# 设置id列为自增长
mysql> alter table t4 modify id int auto_increment;
Query OK, 3 rows affected (0.03 sec)
Records: 3 Duplicates: 0 Warnings: 0# 插入一条记录
mysql> insert into t4(name) values('张磊磊');ysql> select * from t4;
+----+-----------+
| id | name |
+----+-----------+
| 1 | 刘文 |
| 2 | 张磊 |
| 3 | 张磊磊 |
+----+-----------+
3 rows in set (0.00 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.00 sec)mysql> select * from t4;
+----+-----------+
| id | name |
+----+-----------+
| 1 | 刘文 |
| 2 | 张磊 |
| 3 | 张磊磊 |
| 5 | 钱明 |
+----+-----------+
4 rows in set (0.00 sec)
6.9 外键约束
-
作用:限定某个表的某个字段的==引用完整性==
-
概念
-
主表(父表):被引用的表、被参考的表
-
从表(子表):引用别人的表,参考别人的表
-
外键:从表中的某个字段引用自主表的某个字段或多个字段
-
引用键:主表被引用的字段
-
-
外键约束主要定义在从表上,主表则必须是有主键约束或唯一键约束.当定义外键后,要求外键列数据必须在主表的主键列存在或为null.
-
格式:
foreign key (从表的字段名称) references 主表名字(主表的字段名称) # 建立外键关联
- 示例:
-
学生表通过class_id和班级表产生关联,在语义上,class_id称为外键,此时的这个学生表就相当于从表,班级表相当于是主表, 比如我们新增一个class_id为30的学生,但是班级表中得先有id为30的班级,才能在学生表中添加, 要删除班级表中id为20的班级,首先必须保证学生表中没有对应班级为class_id =20的学生.,当然我们也可以新增一个class_id为NULL的学生,表示该学生还没有分配班级, 外键可以为空!
-
注意:
-
主表必须已经存在于数据库中,或者是当前正在创建的表。如果是后一种情况,则主表与从表是同一个表,这样的表称为自参照表,这种结构称为自参照完整性。
-
必须为主表定义主键。
-
主键不能包含空值,但允许在外键中出现空值。也就是说,只要外键的每个非空值出现在指定的主键中,这个外键的内容就是正确的。
-
在主表的表名后面指定列名或列名的组合。这个列或列的组合必须是主表的主键或候选键。
-
外键中列的数目必须和主表的主键中列的数目相同。
-
外键中列的数据类型必须和主表主键中对应列的数据类型相同。
-
-
定义从表的时候,设置外键其实就是设置了一个关系,在从表当中插入数据的时候,会对插入数据进行校验,校验插入的数据是否存在于主表字段当中,外键就是增加了表和表之间的约束关系.
-
示例:
# 定义主表
mysql> create table myclass3(id int primary key, name varchar(20) not null comment '班级名');
Query OK, 0 rows affected (0.02 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.00 sec)
# 定义从表:
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.02 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.00 sec)
# 主表中插入数据
mysql> insert into myclass3 values(10,'C++'),(20,'Java');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0mysql> select * from myclass3;
+----+------+
| id | name |
+----+------+
| 10 | C++ |
| 20 | Java |
+----+------+
2 rows in set (0.00 sec)
# 从表中正常插入数据:
mysql> insert into myclass3_stu values(1,'Li',10),(2,'Sun',20);
Query OK, 2 rows affected (0.00 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.00 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 (`stu_info`.`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.00 sec)mysql> select * from myclass3_stu;
+----+------+----------+
| id | name | class_id |
+----+------+----------+
| 1 | Li | 10 |
| 2 | Sun | 20 |
| 3 | wang | NULL |
+----+------+----------+
3 rows in set (0.00 sec)
6.10 检查约束
-
作用:检查约束(check)是用来检查数据表中字段值有效性的一种手段,一般用于设置值的范围
-
注意
-
设置检查约束时要根据实际情况进行设置,这样能够减少无效数据的输入
-
在默认值和非空约束可看作是特殊的检查约束
-
注意检查约束在8.0.16之前,MySQL默认但不会强制的遵循check约束(写不报错,但是不生效,需要通触发器完成),之后就开始正式支持这个约束了
-
-
示例1:创建表时设置检查约束
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.02 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.00 sec)mysql> insert into t5 values(1,'Li',5984);
Query OK, 1 row affected (0.00 sec)mysql> insert into t5 values(2,'wang',12000);
ERROR 3819 (HY000): Check constraint 't5_chk_1' is violated.
- 示例2:修改表时添加检查约束
# 格式:
alter table 表名 add constraint <检查约束名> check(检查约束)
mysql> alter table t5 add constraint check_id check(id>0);
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
6.11 删除表的约束
删除not null约束alter table 表名 modify 列名 类型;删除unique约束alter table 表名 drop index 惟一约束名;删除primary key约束alter table 表名 drop primary key;删除foreign key约束alter table 表名 drop foreign key 外键名;
6.12 存储引擎
-
数据库存储引擎是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建、查询、更新和删除数据,不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能。现在许多不同的数据库管理系统都支持多种不同的数据引擎。MySQL的核心就是存储引擎。
-
插件式存储引擎是MySQL数据库最重要的特性之一, 用户可以根据应用的需要选择如何存储和索引数据、 是否使用事务等,如:
-
MyISAM:
-
Mysql 5.5之前的默认数据库引擎,最为常用。
-
拥有较高的插入,查询速度,但不支持事务应用于以读写操作为主, 很少更新 、 删除 , 并对事务的完整性、 并发性要求不高的情况
-
-
InnoDB:
-
事务型速记的首选引擎,支持ACID事务,支持行级锁定
-
应用于对事务的完整性要求高,在并发条件下要求数据的一致性的情况。
-
InnoDB:是MySQL的默认数据库引擎
-
-
MEMORY:
-
所有数据置于内存的存储引擎,拥有极高的插入,更新和查询效率。
-
但是会占用和数据量成正比的内存空间。并且其内容会在MYSQL重新启动是会丢失。
-
-
Archive :
-
非常适合存储大量的独立的,作为历史记录的数据。
-
因为它们不经常被读取,则拥有高效的插入速度,但其对查询的支持相对较差
-
-
Federated :将不同的 MySQL 服务器联合起来,逻辑上组成一个完整的数据库。非常适合分布式应用
-
CSV :
-
逻辑上由逗号分割数据的存储引擎。
-
它会在数据库子目录里为每个数据表创建一个 .csv 文件。
-
这是一种普通文本文件,每个数据行占用一个文本行。
-
CSV 存储引擎不支持索引。
-
-
BlackHole: 黑洞引擎,写入的任何数据都会消失,一般用于记录 binlog 做复制的中继
-
ERFORMANCE_SCHEMA:该引擎主要用于收集数据库服务器性能参数。
-
-
默认情况下, 创建表不指定表的存储引擎, 则会使用配置文件的my.ini中default-storage-engine=InnoDB指定的InnoDB
-
查看支持的引擎命令:
show engines \g
-
查看当前默认存储引擎
mysql> show variables like '%storage_engine%';
+---------------------------------+-----------+
| Variable_name | Value |
+---------------------------------+-----------+
| default_storage_engine | InnoDB |
| default_tmp_storage_engine | InnoDB |
| disabled_storage_engines | |
| internal_tmp_mem_storage_engine | TempTable |
+---------------------------------+-----------+
-
在创建表时, 可以指定表的存储引擎:
6.13 总结-完整的建表语句
create table 表名(列名 列类型 [auto_increment] [default 默认值][列约束]...[表约束]) [engine=表类型] [default] charset=字符集;列类型: 该列的数据的存储类型
auto_increment: 自动增尙只能是数值类型的列
defaul 默认值: 设置该列的默认值
约束: 对列的一些限制
engine: 表类型, 也叫表的存储引擎
charset: 设置表的字符篥
6.14 练习
创建销售数据库mydb5_sales
使用该数据库
创建产品表pro_tb (产品编号pro_num int(10) 唯一键 ,产品名pro_name varchar(30) ,产品单价pro_price float(5,2) , 产品规格pro_spe varchar(8) 默认值:件)
创建订单表orders (订单号id int(6) ,客户号customer_id int(4),产品编号pro_num int(10) 外键 ,签订日期signing_date date,金额amount float(5,2) ) , 其中订号单为主键、自增长,金额设置check(大于0)
mysql> create database mydb5_sales;
Query OK, 1 row affected (0.01 sec)mysql> use mydb5_sales;
Database changedmysql> create table pro_tb(pro_num int(10) unique, pro_name varchar(30) not null, pro_price float(5,2) not null, pro_spe varchar(8) default '件' );
Query OK, 0 rows affected, 2 warnings (0.01 sec)mysql> desc pro_tb;
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| pro_num | int | YES | UNI | NULL | |
| pro_name | varchar(30) | NO | | NULL | |
| pro_price | float(5,2) | NO | | NULL | |
| pro_spe | varchar(8) | YES | | 件 | |
+-----------+-------------+------+-----+---------+-------+
4 rows in set (0.01 sec)mysql> create table orders(id int(6) primary key auto_increment, customer_id int(4) not null, pro_num int(10) not null, signing_date date, amount float(5,2), check(amount>0), foreign key(pro_num) references pro_tb(pro_num));
Query OK, 0 rows affected, 4 warnings (0.02 sec)mysql> desc orders;
+--------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| customer_id | int | NO | | NULL | |
| pro_num | int | NO | | NULL | |
| signing_date | date | YES | | NULL | |
| amount | float(5,2) | YES | | NULL | |
+--------------+------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
7.MySQL库表设计:范式
7.1 概念
7.2 第一范式(1NF)
-
原则:库表设计时为了确保原子性,其存储数据具备不可再分性,例:
-
在上述的学生表中,其中有一个
student
学生列,这一列存储的数据则明显不符合第一范式:原子性的规定,因为这一列的数据还可以再拆分为姓名、性别、身高三项数据,因此为了符合第一范式,应该将表结构更改为:
-
如果不去拆分列满足第一范式,会造成什么影响?
-
客户端语言和表之间无法很好的生成映射关系。
-
查询到数据后,需要处理数据时,还需要对
student
字段进行额外拆分。 -
插入数据时,对于第一个字段的值还需要先拼装后才能进行写入。
-
7.3 第二范式(2NF)
原则:表中的所有列,其数据都必须依赖于主键,也就是一张表只存储同一类型的数据,不能有任何一列数据与主键没有关系,例:
虽然此时已经满足了数据库的第一范式,但此刻观察course
课程、score
分数这两列数据,跟前面的几列数据实际上依赖关系并不大,同时也由于这样的结构,导致前面几列的数据出现了大量冗余,所以此时可以再次拆分一下表结构:
经过上述结构优化后,之前的一张表被拆分成学生表、课程表、成绩表三张,每张表中的id
字段作为主键,其他字段都依赖这个主键。无论在那张表中,都可以通过id
主键确定其他字段的信息,每张表的业务属性都具备“唯一性”,也就是每张表都只会描述了“一件事情”,不会存在一张表中会出现两个业务属性。
7.4 第三范式 (3NF)
-
原则:表中每一列数据不能与主键之外的字段有直接关系,例:
比如这张学生表,目前即符合第一范式,也符合第二范式,但看最后的两个字段,department
表示当前学生所属的院校,dean
则表示这个院系的院长是谁。一般来说,一个学生的院长是谁,首先是取决于学生所在的院系的,因此最后的dean
字段明显与department
字段存在依赖关系,因此需要进一步调整表结构。
-
经过进一步的结构优化后,又将原本的学生表拆为了院系表、学生表两张,学生表中则是只存储一个院系
ID
,由院系表存储院系相关的所有数据。至此,学生表中的每个非主键字段与其他非主键字段之间,都是相互独立的,之间不会再存在任何依赖性,所有的字段都依赖于主键。 -
为什么要这样调整?不调整会发生什么问题:
-
当一个院系的院长换人后,需要同时修改学生表中的多条数据。
-
当一个院长离职后,需要删除该院长的记录,会同时删除多条学生信息。
-
......
-
如果设计的表结构,无法满足第三范式,在操作表时就会出现异常,使得整个表较难维护。
-
7.5 三范式小结
-
范式小结
-
1NF:确保原子性,表中每一个列数据都必须是不可再分的字段。
-
2NF:确保唯一性,每张表都只描述一种业务属性,一张表只描述一件事。
-
3NF:确保独立性,表中除主键外,每个字段之间不存在任何依赖,都是独立的。
-
-
没有按照范式设计表时,会存在几个问题
-
整张表数据比较冗余,同一个学生信息会出现多条。
-
表结构特别臃肿,不易于操作,要新增一个学生信息时,需添加大量数据。
-
需要更新其他业务属性的数据时,比如院系院长换人了,需要修改所有学生的记录。
-
-
经过三范式的设计优化后,整个库中的所有表结构,会显得更为优雅,灵活性也会更强。
7.6 巴斯-科德范式(BCNF)
-
概念:
-
前题:一般在一张表中,可以用于区分每行数据的一个列,通常会被咱们设为主键,例如常用的
ID
字段就是如此,这类主键通常被称为单一主键,即一个列组成的主键。但除此之外,还有一个联合主键的概念,也就是由多个列组成的主键 -
巴斯-科德范式也被称为
3.5NF
,是第三范式的补充版 -
第三范式的要求是:任何非主键字段不能与其他非主键字段间存在依赖关系,也就是要求每个非主键字段之间要具备独立性。而巴斯-科德范式在第三范式的基础上,进一步要求:任何主属性不能对其他主键子集存在依赖。
-
大白话:规定了联合主键中的某列值,不能与联合主键中的其他列存在依赖关系
-
例:
-
分析
-
这张学生表,此时假设以
classes
班级字段、class_adviser
班主任字段、name
学生姓名字段,组合成一个联合主键,在这里我们可以通过联合主键,确定学生表中任何一个学生的信息,比如:熊竹老师管的计算机-2201班,哪个竹子同学有多高啊?可以通过上述的联合主键精准定位到表中第一条数据,并且最终能够给出答案为185cm
。 -
出现问题:在这张表中,一条学生信息中的班主任,取决于学生所在的班级,比如「竹子同学、子竹同学」在「计算机-2201班」,所以它们的班主任都是「熊竹老师」,因此班主任字段其实也依赖于班级字段。那会造成什么问题呢?
-
当一个班级的班主任老师换人后,需要同时修改学生表中的多条数据。
-
当一个班主任老师离职后,需要删除该老师的记录,会同时删除多条学生信息。
-
想要增加一个班级时,同时必须添加学生姓名数据,因为主键不允许为空。
-
-
-
通过上述分析可以明显得知,如果联合主键中的一个字段依赖于另一个字段,同样也会造成不小的问题,使得整张表的维护性变差,因此这里需要进一步调整结构:
-
经过结构调整后:
-
原本的学生表则又被拆为了班级表、学生表两张,在学生表中只存储班级
ID
,然后使用classes_id
班级ID
和name
学生姓名两个字段作为联合主键。 -
之前的三个问题也不存在,如换班主任后只需要更改班级表,无需修改学生表中的学生信息;增加班级时,只需要在班级表中新增数据,也不会影响学生表。
-
-
小结:第三范式只要求非主键字段之间,不能存在依赖关系,但没要求联合主键中的字段不能存在依赖,因此第三范式并未考虑完善,巴斯-科德范式修正的就是这点,是对第三范式的补充及完善,修正了第三范式。
7.7 第四范式(4NF)
-
多值依赖:表中的字段之间存在一对多的关系,也就是一个字段的具体值会由多个字段来决定(一个表中至少需要有三个独立的字段才会出现多值依赖问题)
-
示例:
经典的业务,用户角色权限表,各字段含义:
user_name
字段 -- 用户名
role
字段 -- 角色信息:
USER
:普通用户角色。
ADMIN
:管理员角色。
ROOT
:超级管理员角色。
permission
字段 -- 权限信息:
*
:超级管理员拥有的权限级别,*
表示所有。
BACKSTAGE
:管理员拥有的权限级别,表示可以操作后台。
LOGIN
:普通用户拥有的权限级别,表示可以登录访问平台。
-
此时假设我们需要新增一条数据,那表中的权限字段究竟填什么?这个值是需要依赖多个字段决定的,权限来自于角色,而角色则来自于用户。也就是说,一个用户可以拥有多个角色,同时一个角色可以拥有多个权限,所以此时咱们无法单独根据用户名去确定权限值,权限值必须依赖用户、角色两个字段来决定,这种一个字段的值取决于多个字段才能确定的情况,就被称为多值依赖。
-
因此第四范式的定义就是要消除表中的多值依赖关系,上述表格拆分为:
-
观察上述的五张表正是大名鼎鼎的权限五表,将原本的用户角色权限表,拆分成了用户表、角色表、权限表、用户角色关系表、角色权限关系表。
-
经过这次拆分之后,一方面用户表、角色表、权限表中都不会有数据冗余,第二方面无论是要删除亦或新增一个角色、权限时,都不会影响其他表。后面的两张关系表,主要是为了维护用户、角色、权限三者之间的关系。
7.8 第五范式(5NF)/完美范式
-
定义:建立在
4NF
的基础上,进一步消除表中的连接依赖,直到表中的连接依赖都是主键所蕴含的 -
第五范式解决的是无损连接问题,基本没有实际意义,了解即可,因为无损连接很少出现,而且难以察觉
7.9 第六范式(6NF)/域键范式
域键范式,也被称之为终极范式,但目前也仅有学术机构在研究,在生产环境中实际的用途也不大
7.10 反范式
-
概念:不遵循数据库范式设计的结构,就被称为反范式结构。
-
遵循数据库范式设计优点如下:
-
避免了大量的数据冗余
-
节省了大量存储空间
-
表整体结构更为优雅,能让
SQL
操作更加便捷且减少出错。
-
-
但随着范式的级别越高,设计出的结构会更加精细化,原本一张表的数据会被分摊到多张表中存储,表的数量随之越来越多。会存在一个致命问题,也就是当同时需要这些数据时,只能采用联表查询的形式检索数据,有时候甚至为了一个字段的数据,也需要做一次连表查询才能获得。这其中的开销无疑是花费巨大的,尤其是当连接的表不仅两三张而是很多张时,有可能还会造成索引失效,这种情况带来的资源、时间开销简直是一个噩梦,这会严重地影响整个业务系统的性能。
-
因此,也正是由于上述一些问题,在设计库表结构时,我们不一定要
100%
遵守范式准则。这种违反数据库范式的设计方法,就被称之为 反范式设计。 -
设计原则:无论那种范式只要能够对业务有利,那就可以称之为好的设计方案。在设计时千万不要拘泥于规则之内,一定要结合实际业务考虑,遵循业务优先的原则去设计结构。
-
注意:不是所有不遵循数据库范式的结构设计都被称为反范式,反范式设计是指自己知道会破坏范式,但对业务带来好处大于坏处时,刻意设计出破坏范式的结构。
7.11 数据库范式设计总结
-
经过一系列的阐述后,其实不难发现,越到后面的范式,越难令人理解,同时为了让表满足更高级别的范式,越往后付出代价也越大,而且拆分出的表数量也会越多
-
一般项目中仅需满足到第三范式或
BC
范式即可,因为这个度刚刚好,再往后就会因为过于精细化设计,导致整体性能反而下降。 -
控制到第三范式的级别,一方面数据不会有太多冗余,第二方面也不会对性能影响过大。同时,如若打破范式的设定能对业务更有利,那也可以违背范式原则去设计。
-
生产项目中库表结构设计的是否合理,区别如下:
-
不合理的结构设计会造成的问题:
-
数据冗余,会浪费一定程度上的存储空间
-
不便于常规
SQL
操作(例如插入、删除),甚至会出现异常
-
-
合理的结构设计带来的好处:
-
节省空间,
SQL
执行时能节省内存空间,数据存储时能节省磁盘空间 -
数据划分较为合理,
DB
性能整体较高,并且数据也非常完整 -
结构便于维护和进行常规
SQL
操作
-
-
-
各范式之间的递进关系图:
-
范式概念:
-
第一范式:原子性,每个字段的值不能再分。
-
第二范式:唯一性,表内每行数据必须描述同一业务属性的数据。
-
第三范式:独立性,表中每个非主键字段之间不能存在依赖性。
-
巴斯范式:主键字段独立性,联合主键字段之间不能存在依赖性。
-
第四范式:表中字段不能存在多值依赖关系。
-
第五范式:表中字段的数据之间不能存在连接依赖关系。
-
域键范式:试图研究出一个库表设计时的终极完美范式。
-