文章目录
- 前言
- [第 1 章 MySQL 概述](#第 1 章 MySQL 概述)
-
- [1.1 基本概念](#1.1 基本概念)
-
- [1.1.1 数据库是什么?](#1.1.1 数据库是什么?)
- [1.1.2 为什么要用数据库?](#1.1.2 为什么要用数据库?)
- [1.1.3 用普通文件存储行不行?](#1.1.3 用普通文件存储行不行?)
- [1.1.4 MySQL、Oracle、SqlServer 是什么?](#1.1.4 MySQL、Oracle、SqlServer 是什么?)
- [1.1.5 SQL 是什么?](#1.1.5 SQL 是什么?)
- [1.2 MySQL 数据库管理系统](#1.2 MySQL 数据库管理系统)
-
- [1.2.1 关系型数据库和非关系数据库](#1.2.1 关系型数据库和非关系数据库)
- [1.2.2 MySQL 的优点](#1.2.2 MySQL 的优点)
- [1.2.3 MySQL 不同版本](#1.2.3 MySQL 不同版本)
- [1.3 表的关系](#1.3 表的关系)
-
- [1.3.1 一对一](#1.3.1 一对一)
- [1.3.2 一对多](#1.3.2 一对多)
- [1.3.3 多对多](#1.3.3 多对多)
- [第 2 章 SQL 语句简介](#第 2 章 SQL 语句简介)
-
- [2.1 SQL 语句的分类](#2.1 SQL 语句的分类)
- [2.2 SQL 语法规范](#2.2 SQL 语法规范)
- [2.3 SQL 脚本中的注释](#2.3 SQL 脚本中的注释)
- [第 3 章 DDL](#第 3 章 DDL)
-
- [3.1 库相关](#3.1 库相关)
-
- [3.1.1 创建库](#3.1.1 创建库)
- [3.1.2 查看库](#3.1.2 查看库)
- [3.1.3 修改库编码](#3.1.3 修改库编码)
- [3.1.4 使用库](#3.1.4 使用库)
- [3.1.5 删除库](#3.1.5 删除库)
- [3.1.6 示例](#3.1.6 示例)
- [3.2 表相关](#3.2 表相关)
-
- [3.2.1 创建表](#3.2.1 创建表)
- [3.2.2 查看表](#3.2.2 查看表)
- [3.2.3 修改表编码](#3.2.3 修改表编码)
- [3.2.4 修改表结构](#3.2.4 修改表结构)
- [3.2.5 修改表名](#3.2.5 修改表名)
- [3.2.6 删除表](#3.2.6 删除表)
- [3.2.7 示例](#3.2.7 示例)
- [第 4 章 DML](#第 4 章 DML)
-
- [4.1 添加](#4.1 添加)
-
- [4.1.1 只写表名](#4.1.1 只写表名)
- [4.1.2 写表名和字段列表](#4.1.2 写表名和字段列表)
- [4.1.3 示例](#4.1.3 示例)
- [4.2 删除](#4.2 删除)
-
- [4.2.1 删除多条数据](#4.2.1 删除多条数据)
- [4.2.2 删除表中所有数据](#4.2.2 删除表中所有数据)
- [4.2.3 截断表](#4.2.3 截断表)
- [4.2.4 示例](#4.2.4 示例)
- [4.3 修改](#4.3 修改)
-
- [4.3.1 修改部分行数据](#4.3.1 修改部分行数据)
- [4.3.2 修改所有行数据](#4.3.2 修改所有行数据)
- [4.3.3 示例](#4.3.3 示例)
- [4.4 查询](#4.4 查询)
-
- [4.4.1 select 语句](#4.4.1 select 语句)
- [4.4.2 使用别名](#4.4.2 使用别名)
- [4.4.3 结果去重](#4.4.3 结果去重)
- [第 5 章 运算符](#第 5 章 运算符)
-
- [5.1 算数运算符](#5.1 算数运算符)
- [5.2 比较运算符](#5.2 比较运算符)
- [5.3 区间或集合范围比较运算符](#5.3 区间或集合范围比较运算符)
- [5.4 模糊匹配比较运算符](#5.4 模糊匹配比较运算符)
- [5.5 逻辑运算符](#5.5 逻辑运算符)
- [5.6 关于 NULL 值的问题](#5.6 关于 NULL 值的问题)
- [5.7 位运算符](#5.7 位运算符)
- [第 6 章 MySQL 数据类型](#第 6 章 MySQL 数据类型)
-
- [6.1 数值类型](#6.1 数值类型)
-
- [6.1.1 整数类型](#6.1.1 整数类型)
- [6.1.2 浮点数类型](#6.1.2 浮点数类型)
- [6.1.3 BIT 类型](#6.1.3 BIT 类型)
- [6.2 字符串类型](#6.2 字符串类型)
-
- [6.2.1 定长与变长字符串](#6.2.1 定长与变长字符串)
- [6.2.2 枚举与集合](#6.2.2 枚举与集合)
- [6.2.3 文本类型](#6.2.3 文本类型)
- [6.2.4 二进制类型](#6.2.4 二进制类型)
- [6.3 日期时间类型](#6.3 日期时间类型)
- [6.4 其他类型](#6.4 其他类型)
-
- [6.4.1 JSON 类型](#6.4.1 JSON 类型)
- [6.4.2 空间类型](#6.4.2 空间类型)
- 结语
前言
本文系统梳理MySQL核心知识体系,从基础概念到SQL实操,助你快速建立数据库思维,夯实进阶根基。
第 1 章 MySQL 概述
1.1 基本概念
1.1.1 数据库是什么?
数据库(DB:Database):存储数据的地方。
1.1.2 为什么要用数据库?
应用程序产生的数据是在内存中的,如果程序退出或者是断电了,则数据就会消失。使用数据库是为了能够永久保存数据。当然这里指的是非内存数据库。
1.1.3 用普通文件存储行不行?
把数据写入到硬盘上的文件中,当然可以实现持久化的目标,但是不利于后期的检索和管理等。
1.1.4 MySQL、Oracle、SqlServer 是什么?
MySQL、Oracle、SqlServer 都是数据库管理系统(DBMS,Database Management System),是一种操纵和管理数据库的大型软件,例如建立、使用和维护数据库。
1.1.5 SQL 是什么?
SQL 是结构化查询语言(Structure Query Language),专门用来操作/访问数据库的通用语言。
1.2 MySQL 数据库管理系统
在互联网行业,MySQL 数据库毫无疑问已经是最常用的数据库。MySQL 数据库由瑞典 MySQL AB 公司开发。公司名中的 "AB" 是瑞典语 "aktiebolag" 股份公司的首字母缩写。该公司于 2008 年 1 月 16 号被 Sun(Stanford University Network)公司收购。然而 2009 年,SUN 公司又被 Oracle 收购。因此,MySQL 数据库现在隶属于 Oracle(甲骨文)公司。MySQL 中的 "My" 是其发明者(Michael Widenius,通常称为 Monty)根据其女儿的名字来命名的。对这位发明者来说,MySQL 数据库就仿佛是他可爱的女儿。
1.2.1 关系型数据库和非关系数据库
- 关系型数据库 :MySQL、Oracle、SqlServer 等是关系型数据库管理系统。关系型数据库采用关系模型 来组织数据,简单来说,关系模型指的就是二维表格模型,类似于 Excel 工作表。
- 非关系型数据库 :MongoDB、Redis、Elasticsearch 等是非关系型数据库管理系统。非关系型数据库可看成传统关系型数据库的功能阉割版本,基于键值对存储数据,通过减少不常用的功能来提高性能。
1.2.2 MySQL 的优点
- 可移植性:MySQL 数据库几乎支持所有的操作系统,如 Linux、Solaris、FreeBSD、Mac 和 Windows。
- 免费:MySQL 的社区版完全免费,一般中小型网站的开发都选择 MySQL 作为网站数据库。
- 开源:2000 年,MySQL 公布了自己的源代码,并采用 GPL(GNU General Public License)许可协议,正式进入开源的世界。开源意味着可以让更多人审阅和贡献源代码,可以吸纳更多优秀人才的代码成果。
- 关系型数据库:MySQL 可以利用标准 SQL 语法进行查询和操作。
- 速度快、体积小、容易使用:与其他大型数据库的设置和管理相比,其复杂程度较低,易于学习。MySQL 的早期版本(主要使用的是 MyISAM 引擎)在高并发下显得有些力不从心,随着版本的升级优化(主要使用的是 InnoDB 引擎),在实践中也证明了高压力下的可用性。从 2009 年开始,阿里的"去 IOE"备受关注,淘宝 DBA 团队再次从 Oracle 转向 MySQL,其他使用 MySQL 数据库的公司还有 Facebook、Twitter、YouTube、百度、腾讯、去哪儿、魅族等等,自此,MySQL 在市场上占据了很大的份额。
- 安全性和连接性:十分灵活和安全的权限和密码系统,允许基于主机的验证。连接到服务器时,所有的密码传输均采用加密形式,从而保证了密码安全。由于 MySQL 是网络化的,因此可以在因特网上的任何地方访问,提高数据共享的效率。
- 丰富的接口:提供了用于 C、C++、Java、PHP、Python、Ruby 和 Eiffel、Perl 等语言的 API。
- 灵活:MySQL 并不完美,但是却足够灵活,能够适应高要求的环境。同时,MySQL 既可以嵌入到应用程序中,也可以支持数据仓库、内容索引和部署软件、高可用的冗余系统、在线事务处理系统等各种应用类型。
- 存储引擎架构 :MySQL 最重要、最与众不同的特性是它的存储引擎架构 ,这种架构的设计将查询处理(Query Processing)及其他 系统任务(Server Task)和数据的存储/提取 相分离。这种处理和存储分离的设计可以在使用时根据性能、特性,以及其他需求来选择数据存储的方式。MySQL 中同一个数据库,不同的表格可以选择不同的存储引擎。其中使用最多的是 InnoDB 和 MyISAM ,MySQL 5.5 之后 InnoDB 是默认的存储引擎。
1.2.3 MySQL 不同版本
针对不同用户,MySQL 提供三个不同的版本:
| 版本 | 说明 | 费用 | 技术支持 |
|---|---|---|---|
| MySQL Enterprise Server(企业版) | 能够以更高的性价比为企业提供数据仓库应用 | 付费 | 官方提供电话技术支持 |
| MySQL Cluster(集群版) | MySQL 集群是 MySQL 适合于分布式计算环境的高可用、高冗余版本。它采用了 NDB Cluster 存储引擎,允许在 1 个集群中运行多个 MySQL 服务器 | 需配合社区版或企业版使用 | --- |
| MySQL Community Server(社区版) | 在开源 GPL 许可证之下可以自由的使用 | 完全免费 | 官方不提供技术支持 |
1.3 表的关系
在关系数据库管理系统中,很多表之间是有关系的,表之间的关系分为:一对一关系 、一对多关系 和多对多关系。
1.3.1 一对一
该关系中第一个表中的一个行只可以与第二个表中的一个行相关,且第二个表中的一个行也只可以与第一个表中的一个行相关。
示例:"员工基本信息表"和"员工紧急情况联系信息表"。
- "员工基本信息表"中存储的是频繁使用的信息
- "员工紧急情况联系信息表"中存储的是不常用的信息
- 这两个表中的一条记录都代表一个员工的信息
- "员工基本信息表"中的一条记录在"员工紧急情况联系信息表"中只能找到唯一的一条对应记录,反过来也一样,即它们是一一对应关系
这两个表存在相同意义的"员工编号"字段,使它们建立了一对一关系。
1.3.2 一对多
第一个表中的一个行可以与第二个表中的一个或多个行相关,但第二个表中的一个行只可以与第一个表中的一个行相关。
示例 :"部门表"和"员工基本信息表"。"部门表"中的一条记录,在"员工基本信息表"中可以找到一条或多条记录对应,但反过来"员工基本信息表"中的一条记录在"部门表"中只能找到一条记录对应,即一个部门可以有多个员工,但是一个员工只能属于一个部门 。这两个表存在相同意义的"部门编号"字段,使它们建立了一对多关系。
1.3.3 多对多
该关系中第一个表中的一个行可以与第二个表中的一个或多个行相关。第二个表中的一个行也可以与第一个表中的一个或多个行相关。通常两个表的多对多关系会借助第三张表,转换为两个一对多的关系。
示例 :项目系统的"员工基本信息表"和"项目信息表"是多对多关系。一个员工可以参与多个项目,一个项目也可以有多个员工参与,即"员工基本信息表"中一条记录可以与"项目信息表"多条记录对应,反过来"项目信息表"的一条记录也可以与"员工基本信息表"中多条记录对应。它们之间借助第三张"员工项目表"实现关联关系,而"员工基本信息表"与"员工项目表"是一对多关系,"项目信息表"与"员工项目表"也是一对多关系。"员工项目表"中"员工编号"字段与"员工基本信息表"中"员工编号"字段意义相同。"员工项目表"中"项目编号"字段与"项目信息表"中"项目编号"字段意义相同。
第 2 章 SQL 语句简介
2.1 SQL 语句的分类
SQL 语句分为三种类型:
- DDL:数据定义语句(Data Define Language)如创建(create),修改(alter),删除(drop)等。
- DML:数据操作语句,如增(insert),删(delete),改(update),查(select)。因为查询语句使用的非常频繁,因此很多人把查询语句单独划分为 DQL(数据查询语句)。
- DCL:数据控制语句,如 grant,commit,rollback 等。
- 其他语句:use 语句,show 语句,set 语句等。这类的官方文档中一般称为命令。
2.2 SQL 语法规范
- MySQL 的 SQL 语法不区分大小写。
- 命名时尽量使用 26 个英文字母大小写,数字 0-9,下划线,不要使用其他符号。
- 建议不要使用 MySQL 的关键字等来作为表名、字段名、数据库名等,如果不小心使用,请在 SQL 语句中使用 `````(飘号)引起来。
- 数据库和表名、字段名等对象名中间不要包含空格。
- 同一个 MySQL 软件中,数据库不能同名,同一个库中,表不能重名,同一个表中,字段不能重名。
2.3 SQL 脚本中的注释
单行注释 :#(MySQL 特有的)或 -- 注释内容
sql
show databases; #显示库
show databases; -- 显示库
多行注释 :/* 注释内容 */
sql
/*
显示库
*/
show databases;
第 3 章 DDL
3.1 库相关
3.1.1 创建库
sql
create database 数据库名;
3.1.2 查看库
1)查看所有库
sql
show databases;
2)查看某个数据库的详细定义语句
sql
show create database 数据库名;
3.1.3 修改库编码
修改数据库编码只会影响之后新创建的表的默认编码,之前创建的表不会受影响。
sql
alter database 数据库名 character set 字符集名称 collate 字符集对应校对规则;
例如:
sql
alter database db01 character set utf8 collate utf8_general_ci;
3.1.4 使用库
sql
use 数据库名;
3.1.5 删除库
sql
drop database 数据库名;
3.1.6 示例
sql
-- 创建数据库
create database if not exists jdfs;
-- 查看所有数据库
show databases;
-- 查看数据库的创建语句
show create database jdfs;
-- 切换数据库
use jdfs;
-- 修改数据库的字符集为Latin1,Latin1字符集不支持中文
alter database jdfs character set Latin1 collate Latin1_general_ci;
-- 删除数据库
drop database if exists jdfs;
3.2 表相关
3.2.1 创建表
sql
create table [if not exists] 表名(
字段名 数据类型,
字段名 数据类型
);
例如:
sql
create table teacher(
tid int,
tname varchar(5),
salary double,
weight double(5,2),
birthday date,
gender enum('男','女'),
blood enum('A','B','AB','O'),
tel char(11)
);
3.2.2 查看表
1)查看某个数据库的所有表
sql
use 数据库名;
show tables;
或
sql
show tables from 数据库名;
2)查看表的详细定义
sql
show create table 表名;
3)查看表结构
sql
desc 表名;
3.2.3 修改表编码
sql
alter table teacher character set 字符集 collate 校对规则;
例如:
sql
alter table teacher character set utf8mb4 collate utf8mb4_general_ci;
3.2.4 修改表结构
1)添加字段
sql
alter table 表名 add 字段名 数据类型; -- 在表末尾添加字段
alter table 表名 add 字段名 数据类型 first; -- 在表开头添加字段
alter table 表名 add 字段名 数据类型 after 另一个字段; -- 在另一个字段后添加字段
2)删除字段
sql
alter table 表名 drop 字段名;
3)修改字段数据类型
sql
alter table 表名 modify 字段名 新的数据类型;
4)修改字段名
sql
alter table 表名 change 旧字段名 新字段名 新的数据类型;
5)修改字段位置
sql
alter table 表名 modify 字段名 数据类型 first; -- 将字段移动到表的开头
alter table 表名 modify 字段名 数据类型 after 另一个字段; -- 将字段移动到表的另一个字段之后
3.2.5 修改表名
sql
alter table 旧表名 rename 新表名;
或
sql
rename table 旧表名 to 新表名;
3.2.6 删除表
sql
drop table [if exists] 表名;
3.2.7 示例
sql
create database if not exists jdfs;
use jdfs;
-- 创建表
create table if not exists teacher(
id int,
name varchar(20),
gender enum('男','女'),
birthday date,
salary double,
tel varchar(11)
);
-- 查看数据库中所有表
show tables;
-- 查看表结构
desc teacher;
-- 查看建表语句
show create table teacher;
-- 添加字段到表末尾
alter table teacher add address varchar(200);
-- 添加字段到表开头
alter table teacher add age int first;
-- 添加字段到指定位置
alter table teacher add heart_rate float after age;
-- 删除字段
alter table teacher drop address;
-- 修改字段数据类型
alter table teacher modify heart_rate double;
-- 修改字段名
alter table teacher change heart_rate bpm double;
-- 移动字段位置到表开头
alter table teacher modify bpm double first;
-- 移动字段位置到另一个字段之后
alter table teacher modify bpm double after age;
-- 修改表名
alter table teacher rename teacher_info;
-- 删除表
drop table teacher_info;
第 4 章 DML
4.1 添加
4.1.1 只写表名
值列表需与表结构对应。
sql
insert into 表名 values(值列表),(值列表),(值列表);
-- 值列表中的值的顺序、类型、个数必须与表结构一一对应
4.1.2 写表名和字段列表
值列表需与字段列表对应。
sql
insert into 表名(字段列表) values(值列表),(值列表),(值列表);
-- 值列表中的值的顺序、类型、个数必须与字段列表一一对应
4.1.3 示例
sql
create database if not exists jdfs;
use jdfs;
drop table if exists teacher;
create table teacher(
id int,
name varchar(20),
gender enum('男','女'),
birthday date,
salary double,
tel varchar(11)
);
-- 插入一条数据
insert into teacher values(1,'张三','男','1990-01-01',10000,'12345678901');
insert into teacher(id,name,gender) values(2,'李四','男');
select * from teacher;
-- 插入多条数据
insert into teacher values
(3,'王五','男','1990-01-01',10000,'12345678901'),
(4,'赵六','男','1990-01-01',10000,'12345678901'),
(5,'孙七','男','1990-01-01',10000,'12345678901');
insert into teacher(id,name) values(6,'周八'),(7,'吴九'),(8,'郑十');
select * from teacher;
4.2 删除
4.2.1 删除多条数据
sql
delete from 表名 where 条件;
4.2.2 删除表中所有数据
表结构会保留下来。
sql
delete from 表名;
4.2.3 截断表
表结构会保留下来。
sql
truncate 表名;
truncate 表和 delete 表的区别:
delete是一条一条删除记录的。如果在事务中,事务提交之前支持回滚。truncate是把整个表 drop,新建一张,效率更高。就算在事务中,也无法回滚。
4.2.4 示例
sql
-- 删除姓名为郑十的记录
delete from teacher where name="郑十";
select * from teacher;
-- 删除所有记录
delete from teacher;
-- 截断表
truncate teacher;
4.3 修改
4.3.1 修改部分行数据
sql
update 表名 set 字段名 = 值, 字段名 = 值 where 条件;
-- 修改满足条件的行
4.3.2 修改所有行数据
sql
update 表名 set 字段名 = 值, 字段名 = 值;
-- 修改所有行
4.3.3 示例
sql
-- 修改周八的信息
update teacher set gender="男",birthday="1960-01-01",salary=100000,tel="12332132131" where name="周八";
-- 修改所有人的薪资
update teacher set salary=salary+10000;
4.4 查询
4.4.1 select 语句
select 语句是用于查看计算结果、或者查看从数据表中筛选出的数据的。
select 语句的基本语法:
sql
select 常量;
select 表达式;
select 函数;
例如:
sql
select 1;
select 9/2;
select now();
如果要从数据表中筛选数据,需要加 from 子句。from 指定数据来源。字段列表筛选列。
sql
select 字段列表 from 表名;
如果要从数据表中根据条件筛选数据,需要加 from 和 where 子句。where 筛选行。
sql
select 字段列表 from 表名 where 条件;
完整的 select 语句后面可以跟 7 个子句,后面会逐一讲解。
4.4.2 使用别名
在当前 select 语句中给某个字段或表达式计算结果,或表等取个临时名称,便于当前 select 语句的编写和理解。这个临时名称称为别名。
sql
select 字段名1 as "别名1", 字段名2 as "别名2" from 表名 as 表别名;
- 列的别名有空格时需要加双引号。列的别名中没有空格时双引号可以不加。
- 表的别名不能加双引号,表的别名中间不能包含空格。
as大小写都可以,as也完全可以省略。
例如:
sql
select id as 编号, name "姓名" from teacher;
4.4.3 结果去重
MySQL 可以在查询结果中使用 distinct 关键字去重。
sql
select distinct 字段列表 from 表名;
第 5 章 运算符
5.1 算数运算符
| 运算符 | 说明 |
|---|---|
+ |
求和,MySQL 中 + 没有字符串拼接功能 |
- |
减 |
* |
乘 |
/ |
除 |
div |
整除,只保留整数部分 |
% |
模,取余 |
示例:
sql
select 2+3;
select 9/2, 9 div 2;
select 10.1/2.1, 10.1 div 2.1;
select 9%2, 9 mod 2;
select "hello"+"world";
-- NULL 与其他数据类型的运算结果为 NULL
select 2+null;
select "hello"+null;
select date("2020-01-01")+null;
5.2 比较运算符
| 运算符 | 说明 |
|---|---|
> |
大于 |
< |
小于 |
>= |
大于等于 |
<= |
小于等于 |
= |
等于,不能用于 NULL 判断 |
!= 或 <> |
不等于,不能用于 NULL 判断 |
示例:
sql
use jdfs;
-- 查询薪资高于 15000 的员工姓名和薪资
select ename, salary from t_employee where salary>15000;
-- 查询薪资为 9000 的员工的姓名和薪资
select ename, salary from t_employee where salary=9000;
-- 查询地址不在北苑的
select * from t_employee where address!="北苑";
select * from t_employee where address<>"北苑";
5.3 区间或集合范围比较运算符
| 运算符 | 说明 |
|---|---|
between x and y |
处于区间内 |
not between x and y |
不处于区间内 |
in(x,y,z) |
处于集合内 |
not in (x,y,z) |
不处于集合内 |
示例:
sql
use jdfs;
-- 查询薪资在 [10000,15000]
select * from t_employee where salary>=10000 && salary<=15000;
select * from t_employee where salary between 10000 and 15000;
-- 查询薪资不在 [10000,15000]
select * from t_employee where salary not between 10000 and 15000;
-- 查询地址在这几个地方的
select * from t_employee where address in ('北苑', '望京', '龙泽');
-- 查询地址不在这几个地方的
select * from t_employee where address not in ('北苑', '望京', '龙泽');
5.4 模糊匹配比较运算符
| 运算符 | 说明 |
|---|---|
% |
代表任意个字符 |
_ |
代表 1 个字符,如果 2 个下划线就代表 2 个字符 |
示例:
sql
use jdfs;
-- 查询名字有 冰 字的
select * from t_employee where ename like '%冰%';
-- 查询名字以 雨 结尾的
select * from t_employee where ename like '%雨';
-- 查询名字以 李 开头的
select * from t_employee where ename like '李%';
-- 查询名字有 红 这个字,但是 红 的前面只能有 1 个字
select * from t_employee where ename like '_红%';
-- 查询当前 MySQL 数据库的字符集情况
show variables like '%character%';
5.5 逻辑运算符
| 运算符 | 说明 |
|---|---|
&& 或 and |
逻辑与 |
| ` | |
! 或 not |
逻辑非 |
xor |
逻辑异或 |
示例:
sql
use jdfs;
-- 查询薪资高于 15000,并且性别是男的员工
select * from t_employee where salary>15000 and gender='男';
-- 查询薪资高于 15000,或者 did 为 1 的员工
select * from t_employee where salary>15000 || did = 1;
-- 查询薪资不在 [15000,20000] 范围的
select * from t_employee where !(salary between 15000 and 20000);
-- 查询薪资高于 15000,或者 did 为 1 的员工,两者只能满足其一
select * from t_employee where salary>15000 xor did = 1;
select * from t_employee where (salary>15000) ^ (did = 1);
5.6 关于 NULL 值的问题
| 运算符 | 说明 |
|---|---|
is null 或 <=>null |
是 NULL |
is not null |
不是 NULL |
ifnull(x,y) |
当 x 是 NULL 时,用 y 代替 |
示例:
sql
use jdfs;
-- 查询奖金比例为 null 的员工
select * from t_employee where commission_pct is null;
select * from t_employee where commission_pct <=> null;
-- 查询奖金比例不为 null 的员工
select * from t_employee where commission_pct is not null;
-- 查询员工的实发工资,实发工资 = 薪资 + 薪资 * 奖金比例
select ename, salary, commission_pct, salary + salary * ifnull(commission_pct,0) "实发工资" from t_employee;
5.7 位运算符
| 运算符 | 说明 |
|---|---|
<< |
左移 |
>> |
右移 |
& |
按位与 |
| ` | ` |
^ |
按位异或 |
~ |
按位取反 |
第 6 章 MySQL 数据类型
6.1 数值类型
6.1.1 整数类型
| 数据类型 | 字节 | 范围(有符号) | 范围(无符号) | 说明 |
|---|---|---|---|---|
| TINYINT | 1 | -128 ~ 127 | 0 ~ 255 | 小范围整数 |
| SMALLINT | 2 | -32,768 ~ 32,767 | 0 ~ 65,535 | 中小范围整数 |
| MEDIUMINT | 3 | -8,388,608 ~ 8,388,607 | 0 ~ 16,777,215 | 中范围整数 |
| INT/INTEGER | 4 | -2,147,483,648 ~ 2,147,483,647 | 0 ~ 4,294,967,295 | 标准整数类型 |
| BIGINT | 8 | -2^63 ~ 2^63-1 | 0 ~ 2^64-1 | 大范围整数 |
对于整数类型,MySQL 还支持在类型名称后面加小括号(M),而小括号中的 M 表示显示宽度 ,M 的取值范围是(0, 255)。int(M) 这个 M 在字段的属性中指定了 unsigned(无符号)和 zerofill(零填充)的情况下才有意义。表示当整数值不够 M 位时,用 0 填充。如果整数值超过 M 位但是没有超过当前数据类型的范围时,就按照实际位数存储。当 M 宽度超过当前数据类型可存储数值范围的最大宽度时,也是以实际存储范围为准。
MySQL 8 之前,int 没有指定(M),默认显示(11)。最多能存储和显示 11 位整数。从 MySQL 8.0.17 开始,整数数据类型不推荐使用显示宽度属性,默认显示 int。
sql
-- 创建表
create table t_int(
i1 int,
i2 int(2) -- 没有 unsigned zerofill,(2)没有意义
);
-- 查看表结构
desc t_int;
-- 创建表
create table t_int2(
i1 int,
i2 int(2) unsigned zerofill
);
-- 查看表结构
desc t_int2;
-- 添加数据
insert into t_int2 values(1234,1234);
-- 查询数据
select * from t_int2;
-- 添加数据
insert into t_int2 values(1,1);
-- 查询数据
select * from t_int2;
6.1.2 浮点数类型
| 数据类型 | 字节 | 范围 | 说明 |
|---|---|---|---|
| FLOAT | 4 | ±3.402823466E+38(~7位精度) | 单精度浮点数 |
| DOUBLE | 8 | ±1.7976931348623157E+308(~16位精度) | 双精度浮点数 |
| DECIMAL/NUMERIC | 可变 | 用户定义精度和范围 | 精确小数,常用于财务计算 |
MySQL 中使用浮点数和定点数来表示小数。浮点数有两种类型:单精度浮点数(FLOAT)和双精度浮点数(DOUBLE),定点数只有 DECIMAL。
浮点数和定点数都可以用 (M, D) 来表示:
- M 是精度,表示该值总共显示 M 位,包括整数位和小数位,对于 FLOAT 和 DOUBLE 类型来说,M 取值范围为 0~255,而对于 DECIMAL 来说,M 取值范围为 0~65。
- D 是标度 ,表示小数的位数,取值范围为 0~30,同时必须
<=M。
FLOAT 和 DOUBLE 类型在不指定(M,D)时,默认会按照实际的精度来显示。DECIMAL 类型在不指定(M, D)时,默认为 (10, 0),即只保留整数部分。例如,定义 DECIMAL(5,2) 的类型,表示该列取值范围是 -999.99~999.99。如果用户插入数据的小数部分位数超过 D 位,MySQL 会四舍五入处理,但是如果用户插入数据的整数部分位数超过 M-D 位,则会报 Out of range 的错误。
DECIMAL 实际是以字符串形式存放的,在对精度要求比较高的时候(如货币、科学数据等)使用 DECIMAL 类型会比较好。浮点数相对于定点数的优点是在长度一定的情况下,浮点数能够表示更大的数据范围,它的缺点是会引起精度问题。
sql
-- 创建表
create table t_double(
d1 double,
d2 double(5,2) -- -999.99~999.99
);
-- 查看表结构
desc t_double;
-- 添加数据
insert into t_double values(2.5,2.5);
-- 查询数据
select * from t_double;
-- 添加数据
insert into t_double values(2.5526,2.5526);
insert into t_double values(2.5586,2.5586);
-- 查询数据
select * from t_double;
-- 添加数据
insert into t_double values(12852.5526,12852.5526);
-- d2字段整数部分超过(5-2=3)位,添加失败
-- 创建表
create table t_decimal(
d1 decimal, -- 没有指定(M,D)默认是(10,0)
d2 decimal(5,2)
);
-- 查看表结构
desc t_decimal;
-- 添加数据
insert into t_decimal values(2.5,2.5);
-- 查询数据
select * from t_decimal;
-- 把小数赋值给整数类型的字段时,会截断小数部分,考虑四舍五入
insert into t_int2 values(1.5,1.5);
select * from t_int2;
6.1.3 BIT 类型
BIT 是一种存储位数据的类型,每个字段的长度可以指定为 1 到 64 位。数据以位流的形式存储,并以字节(byte)对齐。即使只存储 1 位,最小存储单元也是 1 字节。
可以使用十六进制、二进制或整数形式插入数据。插入值的位数不能超过定义的位数,否则会报错。
查询 BIT 字段时,MySQL 会以二进制格式显示数据。如果需要以整数形式显示,可以使用 BIN() 或 CONV()。
可以对 BIT 数据进行逻辑运算,例如 AND,OR,XOR 等。
sql
-- 创建表
create table t_bit(
b1 bit, -- 没有指定(M),默认是 1 位二进制
b2 bit(4) -- 能够存储 4 位二进制 0000~1111
);
-- 查看表结构
desc t_bit;
-- 添加数据
insert into t_bit values(1,1);
-- 查询数据
select * from t_bit;
-- 显示二进制值,需要使用 bin 函数
select bin(b1),bin(b2) from t_bit;
-- 添加数据
insert into t_bit values(2,2);
-- values()中是十进制值,需要转为二进制存储,2 对应 10,超过 1 位,b1 存不下
-- 添加数据
insert into t_bit values(1,8);
-- 查看数据
select * from t_bit;
-- 显示二进制值,需要使用 bin 函数
select conv(b1,2,10),conv(b2,2,10) from t_bit;
-- 添加数据
insert into t_bit values(1,16); -- 16 的二进制 10000
6.2 字符串类型
6.2.1 定长与变长字符串
| 数据类型 | 最大长度 | 说明 |
|---|---|---|
| CHAR(M) | 0 ~ 255 字符 | 定长字符串,长度不足会补空格 |
| VARCHAR(M) | 0 ~ 65535 字节 | 变长字符串,存储长度需加 1 或 2 字节 |
CHAR(M) 为固定长度的字符串,M 表示最多能存储的字符数,取值范围是 0~255 个字符,如果未指定(M)表示只能存储 1 个字符。例如 CHAR(4) 定义了一个固定长度的字符串列,其包含的字符个数最大为 4,如果存储的值少于 4 个字符,右侧将用空格填充以达到指定的长度,当查询显示 CHAR 值时,尾部的空格将被删掉。
VARCHAR(M) 为可变长度的字符串,M 表示最多能存储的字符数,M 的范围由最长的行的大小(通常是 65535)和使用的字符集确定。例如 utf8mb4 字符编码单个字符所需最长字节值为 4 个字节,所以 M 的范围是 [0,16383]。而 VARCHAR 类型的字段实际占用的空间为字符串的实际长度加 1 或 2 个字节,这 1 或 2 个字节用于描述字符串值的实际字节数,即字符串值在 [0,255] 个字节范围内,那么额外增加 1 个字节,否则需要额外增加 2 个字节。在 VARCHAR 后面的 M 必须指定。
例如,身份证号、手机号码、QQ 号、用户名 username、密码 password、银行卡号等固定长度的文本字符串适合使用 CHAR 类型,而评论、朋友圈、微博不定长度的文本字符串更适合使用 VARCHAR 类型。
另外,存储引擎对于选择 CHAR 和 VARCHAR 是有影响的:
- 对于 MyISAM 存储引擎,最好使用固定长度的数据列代替可变长度的数据列。这样可以使整个表静态化,从而使数据检索更快,用空间换时间。
- 对于 InnoDB 存储引擎,使用可变长度的数据列,因为 InnoDB 数据表的存储格式不分固定长度和可变长度,因此使用 CHAR 不一定比使用 VARCHAR 更好,但由于 VARCHAR 是按照实际的长度存储的,比较节省空间,所以对磁盘 I/O 和数据存储总量比较好。
sql
drop table if exists t_char;
create table t_char (
c1 char,
c2 char(3)
);
insert into t_char values('男','女'); -- 成功
insert into t_char values('节点飞思','节点飞思'); -- 失败
insert into t_char values('男','节点飞思'); -- 成功
select * from t_char;
drop table if exists t_char;
create table t_char (
c1 varchar -- 错误
);
create table t_char (
c1 varchar(3) -- 最多不超过 3 个字符
);
insert into t_char values('节点飞思');
insert into t_char values('节点飞思真好'); -- 失败
drop table if exists t_char;
create table t_char (
name varchar(65535)
);
-- 错误,字符串过长
6.2.2 枚举与集合
| 特性 | ENUM | SET |
|---|---|---|
| 存储值个数 | 单选(一个值) | 多选(一个或多个值) |
| 存储方式 | 数字索引 | 位图 |
| 选项个数限制 | 最多 65,535 个 | 最多 64 个 |
| 插入非法值 | 转为空字符串或报错 | 忽略非法值 |
| 适用场景 | 需要单选的状态字段(如性别) | 多选标签(如用户角色) |
有时候我们指定在固定的几个值范围内选择一个或多个,那么就需要使用 ENUM 枚举类型和 SET 集合类型了。比如性别只有"男"或"女";上下班交通方式可以有"地铁"、"公交"、"出租车"、"自行车"、"步行"等。
枚举和集合类型字段声明的语法格式如下:
- 字段名 ENUM(值1,值2,值3)
- 字段名 SET(值1,值2,值3)
ENUM 类型的字段在赋值时,只能在指定的枚举列表中取值,而且一次只能取一个。枚举列表最多可以有 65535 个成员。ENUM 值在内部用整数表示,每个枚举值均有一个索引值,MySQL 存储的就是这个索引编号。
SET 类型的字段在赋值时,可从定义的值列表中选择 1 个或多个值的组合。SET 列最多可以有 64 个成员。SET 值在内部也用整数表示,分别是 1, 2, 4, 8......,都是 2 的 n 次方值。因为这些整数值对应的二进制都是只有 1 位是 1,其余是 0。
sql
drop table if exists t_enum;
create table t_enum (
gender enum('男','女'),
hobby set('睡觉','打游戏','运动','写代码')
);
desc t_enum;
insert into t_enum values('男','睡觉,打游戏'); -- 成功
insert into t_enum values('男,女','睡觉,打游戏'); -- 失败
insert into t_enum values('妖','睡觉,打游戏'); -- 失败
insert into t_enum values('男','睡觉,打游戏,吃饭'); -- 失败
select * from t_enum;
insert into t_enum values(2, 2);
select * from t_enum;
insert into t_enum values(1, 5);
-- 5(0101)是 1(0001)、4(0100)的组合
select * from t_enum;
insert into t_enum values(1, 7);
-- 7(0111)是 1(0001)、2(0010)、4(0100)的组合
select * from t_enum;
insert into t_enum values(2, 15);
select * from t_enum;
6.2.3 文本类型
| 数据类型 | 最大长度 | 说明 |
|---|---|---|
| TINYTEXT | 255 字节 | 小文本 |
| TEXT | 65,535 字节(64 KB) | 常规文本 |
| MEDIUMTEXT | 16,777,215 字节 | 中等大小文本 |
| LONGTEXT | 4,294,967,295 字节 | 超大文本 |
6.2.4 二进制类型
| 数据类型 | 最大长度 | 说明 |
|---|---|---|
| BINARY(M) | 0 ~ 255 字节 | 定长二进制数据 |
| VARBINARY(M) | 0 ~ 65535 字节 | 变长二进制数据 |
| BLOB | 0 ~ 4 GB | 用于存储二进制大对象 |
BINARY 和 VARBINARY 类似于 CHAR 和 VARCHAR,只是它们存储的是二进制字符串。
BINARY(M) 为固定长度的二进制字符串,M 表示最多能存储的字节数,取值范围是 0~255 个字节,如果未指定(M)表示只能存储 1 个字节。例如 BINARY(8),表示最多能存储 8 个字节,如果字段值不足(M)个字节,将在右边填充'\0'以补齐指定长度。
VARBINARY(M) 为可变长度的二进制字符串,M 表示最多能存储的字节数,总字节数不能超过行的字节长度限制 65535,另外还要考虑额外字节开销,VARBINARY 类型的数据除了存储数据本身外,还需要 1 或 2 个字节来存储数据的字节数。VARBINARY 类型和 VARCHAR 类型一样必须指定(M),否则报错。
6.3 日期时间类型
| 数据类型 | 字节 | 范围 | 格式 | 说明 |
|---|---|---|---|---|
| DATE | 3 | 1000-01-01 ~ 9999-12-31 | YYYY-MM-DD | 日期 |
| DATETIME | 8 | 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 日期时间,精确到秒 |
| TIMESTAMP | 4 | 1970-01-01 00:00:01 UTC ~ 2038-01-19 03:14:07 UTC | YYYY-MM-DD HH:MM:SS | 时间戳,受时区影响 |
| TIME | 3 | -838:59:59 ~ 838:59:59 | HH:MM:SS | 时间 |
| YEAR | 1 | 1901 ~ 2155 | YYYY | 年份 |
如果仅仅是表示年份信息,可以只使用 YEAR 类型,这样更节省空间,格式为"YYYY",例如"2022"。YEAR 允许的值范围是 1901~2155。YEAR 还有格式为"YY" 2 位数字的形式,值是 00~69,表示 2000~2069 年,值是 70~99,表示 1970~1999 年,从 MySQL 5.5.27 开始,2 位格式的 YEAR 已经不推荐使用。YEAR 默认格式就是"YYYY",没必要写成 YEAR(4),从 MySQL 8.0.19 开始,不推荐使用指定显示宽度的 YEAR(4) 数据类型。这个 0 年,如果是以整数的 0 添加的话,那么是 0000 年,如果是以日期/字符串的'0'添加的话,是 2000 年。
如果要表示年月日,可以使用 DATE 类型,格式为"YYYY-MM-DD",例如"2022-02-04"。
如果要表示时分秒,可以使用 TIME 类型,格式为"HH:MM:SS",例如"10:08:08"。
如果要表示年月日时分秒的完整日期时间,可以使用 DATETIME 类型,格式为"YYYY-MM-DD HH:MM:SS",例如"2022-02-04 10:08:08"。
如果需要经常插入或更新日期时间为系统日期时间,则通常使用 TIMESTAMP 类型,格式为"YYYY-MM-DD HH:MM:SS",例如"2022-02-04 10:08:08"。TIMESTAMP 与 DATETIME 的区别在于 TIMESTAMP 的取值范围小,只支持 1970-01-01 00:00:01 UTC 至 2038-01-19 03:14:07 UTC 范围的日期时间值,其中 UTC 是世界标准时间,并且 TIMESTAMP 类型的日期时间值在存储时会将当前时区的日期时间值转换为时间标准时间值,检索时再转换回当前时区的日期时间值,这会更友好。而 DATETIME 则只能反映出插入时当地的时区,其他时区的人查看数据必然会有误差的。另外,TIMESTAMP 的属性受 MySQL 版本和服务器 SQLMode 的影响很大。
sql
drop table if exists t_date;
create table t_date (
d1 datetime,
d2 timestamp
);
insert into t_date values('2021-9-2 14:45:52','2021-9-2 14:45:52');
select * from t_date;
-- 修改当前的时区
set time_zone = '+2:00';
insert into t_date values('202192144552','202192144552'); -- 格式错误
insert into t_date values('20210902144552','20210902144552');
insert into t_date values('2021&9&2 14%45%52','2021#9#2 14@45@52');
select * from t_date;
drop table if exists t_date;
create table t_date (
d year
);
insert into t_date values(2021),(85),(22),(69),(0),('0');
select * from t_date;
6.4 其他类型
6.4.1 JSON 类型
在 MySQL 5.7 之前,如果需要在数据库中存储 JSON 数据只能使用 VARCHAR 或 TEXT 字符串类型。从 5.7.8 版本之后开始支持 JSON 数据类型。
6.4.2 空间类型
MySQL 空间类型扩展支持地理特征的生成、存储和分析。这里的地理特征表示世界上具有位置的任何东西,可以是一个实体,例如一座山;可以是空间,例如一座办公楼;也可以是一个可定义的位置,例如一个十字路口等等。现在的应用程序开发中空间数据的存储越来越多了,例如,钉钉的打卡位置是否在办公区域范围内,滴滴打车的位置、路线等。MySQL 提供了非常丰富的空间函数以支持各种空间数据的查询和处理。
MySQL 中使用 Geometry(几何)来表示所有地理特征。Geometry 指一个点或点的集合,代表世界上任何具有位置的事物。MySQL 的空间数据类型(Spatial Data Type)对应于 OpenGIS 类,包括 GEOMETRY、POINT、LINESTRING、POLYGON 等单值类型以及 MULTIPOINT、MULTILINESTRING、MULTIPOLYGON、GEOMETRYCOLLECTION 存放不同几何值的集合类型。
有关MySQL的进阶请点击到此链接观看MySQL进阶
结语
掌握这些基础,你已迈出MySQL精进的第一步。理论结合实践,方能在实际开发中游刃有余。