# MySQL

# 参考文档

# 图形化界面

  • DBeaver,开源免费,Linux 首选。
  • HeidiSQL,一款精简版的,特别好用。
  • Navicat。
  • SQLyog。

# 数据类型

MySQL 中的数据类型有很多,主要分为三类:

  • 数值类型。
  • 字符串类型。
  • 日期时间类型。

# 数值类型

每种类型都分为有符号(SIGNED)和无符号(UNSIGNED)类型,比如定义一个无符号的小整数 age TINYINT UNSIGNED

类型 大小 描述
TINYINT 1 byte 小整数
SMALLINT 2 b 大整数
MEDIUMINT 3 b 大整数
INT or INTEGER 4 b 大整数
BIGINT 8 b 极大整数
FLOAT 4b 单精度浮点数值
DOUBLE 8b 双精度浮点数值
DECIMAL 小数值(精确定点数)

# 字符串类型

类型 大小 描述
CHAR 0-255 bytes 定长字符串
VARCHAR 0-65535 bytes 变长字符串
TINYBLOB 0-255 bytes 不超过 255 个字符的二进制数据
TINYTEXT 0-255 bytes 短文本字符串
BLOB 0-65535 bytes 二进制形式的长文本数据
TEXT 0-65535 bytes 长文本数据
MEDIUMBLOB 0-16777215 bytes 二进制形式的中等长度文本数据
MEDIUM TEXT 0-16777215 bytes 中等长度长文本数据
LONGBLOB 0-4294967295 bytes 二进制形式的极大文本数据
LONGTEXT 0-4294967295 bytes 极大文本数据

注意: 正常使用中,需要指定字符串的长度,比如 chart(10) 表示最多只能存储 10 个字符,超过报错。假如 char(10) 中只存储了一个字符,依然会占用 10 个空间,其他的用空格补位。varchar(10) 中如果如果存储小于 10 个字符的内容,存储的多大就是多大。

# 日期时间类型

类型 大小 范围 格式 描述
DATE 3 1000-01-01 至 9999-12-31 YYYY-MM-DD 日期
TIME 3 -838:59:59 至 838:59:59 HH:MM:SS 时间值或持续时间
YEAR 1 1901 至 2155 YYYY 年份值
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 至 2038-01-19 03:14:07 混合日期和时间值,时间戳

# SQL

# 语法

  • SQL 语句以分号结尾,可以单行也可多行。
  • SQL 语句可以使用空格/缩进来增强语句的可读性。
  • MySQL 数据库的 SQL 语句不区分大小写,关键字建议大写。
  • 注释:
    • 单行注释:-- xxx 或者 # xxx(MySQL 独有)。
    • 多行内容: /* xxx */

# 分类

  • DDl,Data Definition Language,数据定义语言,用来定义数据库对象(数据库、表、字段)。
  • DML,Data Manipulation Language,数据操作语言,用来对数据库表中的数据进行增删改。
  • DQL,Data Query Language,数据查询语言,用来查询数据库中表的记录
  • DCL,Data Control Language,数据控制语言,用来创建数据库用户、控制数据库的访问权限。

# DDL

Data Definition Language,数据定义语言,用来定义数据库对象(数据库、表、字段)。

# 操作数据库

查询所有数据库:SHOW DATABASES;

查询当前数据库:SELECT DATABASES();

创建数据库:CREATE DATEABASE [IF NOT EXISTS] db_name [DEFAULT CHARSET 字符集] [COLLATE 排序规则];

  • 例如:CREATE DATABASE if not exists user;

删除数据库:DROP DATABASE [IF EXIST] db_name;

使用数据库:USE db_name;

# 操作表

查询所有表:SHOW TABLES;

创建表结构:

CREATE TABLE tb_name (
    字段1 字段1类型[COMMENT 字段1注释],
    字段2 字段2类型[COMMENT 字段2注释]...
)[COMMENT 表注释];
# 示例
create table m_user(
-> id int comment "no",
-> age int comment "age"
-> ) comment 'user table';
1
2
3
4
5
6
7
8
9
10

查询表结构:DESC tb_name;

查询指定表的建表语句:SHOW CREATE TABLE tb_name;

修改表:

  • 添加字段(ADD):ALTER TABLE 表名 ADD 字段名 类型(长度) [COMMENT 注释] [约束];
  • 修改字段名和类型(CHANGE):ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型(长度) [COMMENT 注释] [约束];
  • 修改字段数据类型(MODIFY):ALTER TABLE 表名 MODIFY 字段名 新类型(长度);
  • 删除字段(DROP):ALTER TABLE 表名 DROP 字段名;
  • 修改表名(RENAME):ALTER TABLE 表名 RENAME TO 新表名;。 // TO 可省

删除表:DROP TABLE [IF EXISTS] 表名;

删除表,然后重建该表(即清除表数据,但保留表结构):TRUNCATE TABLE 表名;

# DML

Data Manipulation Language,数据操作语言,用来对数据库表中的数据进行增删改。

  • 添加数据 INSERT
  • 修改数据 UPDATE
  • 删除数据 DELETE

# 添加数据/INSERT

  • 所有字段 添加数据:INSERT INTO 表名 VALUES (值1,值2,...);
  • 指定字段 添加数据:INSERT INTO 表名 (字段名1,字段名2,...) VALUES (值1,值2,...);
  • 批量添加数据:
    • INSETR INTO 表名 (字段1,字段2,...) VALUES (值1,值2,...), (值1,值2,...);
    • INSETR INTO 表名 VALUES (值1,值2,...),(值1,值2,...);

注意: 插入的字符串或者时间格式的值需要加在引号里面。

# 修改数据/UPDATE

UPDATE 表名 SET 字段1=值1,字段2=值2,... [WHERE 条件];,若无修改条件,默认改全表。

# 删除数据/DELETE

DELETE FROM 表名 [WHERE 条件];,若无条件,默认改全表。

  • 只能删除整条记录,不能删除一条记录中的某个字段的值,如果想要删除某个字段的值,可以使用 update 某个字段为 null。

# DQL

Data Query Language,数据查询语言,用来查询数据库中表的记录

查询用关键字 SELECT,查询语法为:

// 数字代表实际执行顺序,也就说返回字段是在分组过滤后才做的。
SELECT 字段列表 // 4
FROM 表名列表 // 1
WHERE 条件列表 // 2
GROUP BY 分组字段列表 // 3
HAVING 分组后条件列表 // 
ORDER BY 排序字段列表 // 5
LIMIT 分页参数 // 6
1
2
3
4
5
6
7
8

# 基本查询/别名/去重

  • SELECT * FROM 表名;
  • SELECT 字段1, 字段2, ... FROM 表名;

设置别名:

  • SELECT 字段1 [AS 别名1],字段2 [AS 别名2] ... FROM 表名; // AS 可省

去重:

  • SELECT DISTINCT 字段列表 FROM 表名;

# 条件查询

使用关键字 WHERE,语法为:SELECT 字段列表 FROM 表名 WHERE 条件列表;

可用条件有:

符号 功能
> 大于
>= 大于等于
< 小于
<= 小于等于
= 等于
<> 或 != 不等于
BETWEEN...AND... 在某个范围内(含最小最大值)
IN(...) 在 in 之后的列表中的值,多选一
LIKE 占位符 模糊匹配( _ 匹配单个字符,% 匹配多个字符)
IS NULL 是 NULL
AND 或 && 并条件
OR 或 || 或条件
NOT 或 ! 非条件,取反
  • BETWEEN 小值 AND 大值 <==> >= 小值 && <= 大值
  • 查询名字为两个字的用户:SELECT * FROM user WHERE name LIKE '__'

# 聚合函数

将一列数据作为一个整体,进行纵向计算。

语法: SELECT 聚合函数(字段列表) FROM 表名;

常用的聚合函数有:

函数 作用
count 统计数量
max 最大值
min 最小值
avg 平均值
sum 求和

注意: NULL 值不参与聚合运算。

# 示例

  • 统计用户总数:SELECT COUNT(*) FROM user;
  • 统计用户总数:SELECT AVG(age) FROM user;

# 分组查询

关键字 GROUP BYSELECT 字段列表 FROM 表名 [WHERE 条件] GROUP BY 分组字段 [HAVING 分组后过滤条件];

注意: WHERE > 聚合函数 > HAVING

# 排序查询

关键字 ORDER BYSELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1,字段2 排序方式2;

排序方式分为:

  • ASC 升序(默认)。
  • DESC 降序。

多个字段排序规则:先按照第一个字段排序,第一个字段值相同时,再按照第二个字段排序。

# 示例

按照年龄升序排序:SELECT * FROM user ORDER BY age ASC;

# 分页查询

分页查询的实现每个数据库是不一样的,在 MySQL 中使用的是关键字 LIMIT

SELECT * FROM 表名 LIMIT 起始索引,要查询条数

  • 起始索引 0 开始,

# DQL-多表查询

多表查询主要分为 连接查询(交集)、联合查询(并集)和 嵌套查询(子查询)。

# 连接查询

连接查询共分为:

  • 内连接,只取两表交集
  • 外连接
    • 左外连接,查询左表所有数据
    • 右外连接,查询右表所有数据
  • 自连接??

连接查询需要指定两个表的关联条件,用来消除笛卡尔积。笛卡尔积:集合 A 和 集合 B 的所有排列组合值。

# 内连接

内连接只返回集合 A 和集合 B 的交集,分为 2 种:

  • 隐式内连接 SELECT * FROM t1, t2 WHERE t1.xx = t2.yy
  • 显式内连接 SELECT * FROM t1 [INNER] JOIN t2 ON t1.xx = t2.yy
-- 隐式内连接
select user.*, ur.name from user, user_role ur where user.role_id = ur.id;
-- 显式内连接,inner 可省略
select * from user [inner] join user_role ur on user.role_id = ur.id;
1
2
3
4

# 外连接

外连接分为 2 种:

  • 左外连接,SELECT * FROM t1 LEFT [OUTER] JOIN t2 ON t1.xx = t2.yy
  • 右外连接,SELECT * FROM t1 RIGHT [OUTER] JOIN t2 ON t1.xx = t2.yy

左连接返回左表所有数据和交集数据,右连接亦然。

# 自连接

自连接是一种特殊的外连接,自己连接自己

语法:SELECT * FROM t1 alias1 JOIN t1 alias2 ON alias1.learder_id = alias2.id

自连接可以是内连接也可以是外连接。

# 联合查询

联合查询就是将多次查询合并,返回一个新的结果集,关键字 unionunion all

  • union,查询到的结果去重处理。
  • union all,查询到的结果只是简单的拼接在一起,不会去重处理。

联合查询的多张表的列数和字段类型必须保持一致。

SELECT * DROM t1
UNION [ALL]
SELECT * FROM t2;
1
2
3

# 嵌套查询/子查询

嵌套查询也叫子查询。用 () 括起来。

语法:SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);

子查询的外部语句可以是 SELECTINSERTUPDATEDELETE 种任意一种。

--> 根据查询结果不同,可以分为以下几种:

  • 标量子查询,子查询返回的结果是一个单个的值
  • 列子查询,返回结果是一列(可以多行)
  • 行子查询,返回结果是一行(可以多列)
  • 表子查询,返回结果是多行多列的

--> 根据子查询位置,可以分为:

  • WHERE 之后
  • FROM 之后
  • SELECT 之后

# 标量子查询

子查询返回的结果是一个单个的值

# 列子查询

子查询返回的结果是一列(可以多行)

select * from user where roleInfo in (select ...)
1

# 行子查询

子查询返回的结果是一行(可以多列)

select * from user where id = 1 and age = 2;
-- 等同于
select * from user where (id, age) = (1, 2);

select * from user where (id, age) = (select ...)
1
2
3
4
5

# 表子查询

子查询返回的结果是多行多列

示例:查询和张三、李四的职位和工资相同的员工信息。

-- 1. 查询张三、李四的职位和工资
select job, salary from emp where name = '张三' or name = '李四';
-- 返回结果是一个多行多列的
-- job      salary
-- 开发      1800
-- 项目经理  3500
-- 2. 查询员工信息
select * from emp where (job, salary) in (select ...)
1
2
3
4
5
6
7
8

查询结果可以当做临时表进行操作,查询的结果不仅还可以放在 from 后,作为一张表进行查询。

# DCL

Data Control Language,数据控制语言,用来创建数据库用户、控制数据库的访问权限。

# 用户管理

MySQL 数据库的用户存放在系统数据库 mysql 中的 user 表中。

# 查询用户

USE mysql;
SELECT * FROM user;
1
2

# 创建用户

CREATE USER '用户名@主机名' INDENTIFIED BY '密码';

# 修改用户密码

ALTER USER '用户名@主机名' INDENTIFIED WITH mysql_native_password BY '新密码';

# 删除用户

DROP USER '用户名@主机名';

# 权限控制

MySQL 中定义了很多权限,常用的权限如下:

权限 说明
ALL,ALL PRIVILEGES 所有权限
SELECT 查询数据
INSERT 插入数据
UPDATE 更新数据
DELETE 删除数据
ALTER 修改表
DROP 删除数据库/表/视图
CREATE 创建数据库/表

# 查询权限

SHOW GRANTS FOR '用户名@主机名';

# 授予权限

GRANTS 权限列表 ON 数据库.表名 TO '用户名@主机名';

# 撤销权限

REVOKE 权限列表 ON 数据库.表名 FROM '用户名@主机名';

# 函数

# 字符串函数

  • CONCAT(S1, S2, S3...),拼接字符串。
  • LOWER(str)
  • UPPER(str)
  • LPAD(str, n, pad),左填充,用 pad 对 str 的左边进行填充,达到 n 个字符串长度。
  • RPAD(str, n, pad)
  • TRIM(str),去除字符串头尾的空格。
  • SUBSTRING(str, start, length),从 start 开始 length 长度。

# 数值函数

  • CEIL(x),向上取整。
  • FLOOR(x),向下取整。
  • MOD(x,y),返回 x/y 的模(取余数)。
  • RAND(x),返回 0~1 内的随机数。
  • ROUND(x, y),求参数 x 的四舍五入的值,保留 y 位小数。

生成 6 位验证码:SELECT LPAD( CEIL (RAND()*1000000),6,0)

# 日期函数

  • CURDATE(), current date。
  • CURTIME(), current time。
  • NOW(), current datetime。
  • YEAR(date)
  • MONTH(date)
  • DAY(date)
  • DATE_ADD(date, INTERVAL expr type),返回一个日期/时间值加上一个时间间隔 expr 后的时间值。
    • 70 天后的时间:SELECT DATE_ADD(NOW(), INTERVAL 70 DAY);
  • DATEDIFF(date1, date2)date1 - date2,返回起止时间的天数。

# 流程函数

  • IF(boolValue, t, f)
  • IFNULL(value1, value2),如果不为空返回 val1,否则返回 value 2,类似 getIfBlank() 方法。
  • CASE WHEN [val1] THEN [res1] ... ELSE [defaultValue] END,如果 val1 == true,则返回 res1,否则返回 default 默认值。
  • CASE [expr] WHEN [val1] THEN [res1] ... ELSE [defaultValue] END,如果 expr 的值等于 val1,则返回 res1,否则返回 default 默认值。

示例1:

SELECT
	nickname ,
	mobile ,
	(CASE
		address when '北京' then '一线'
		when '上海' THEN '一线'
		ELSE '二线'
	end) as 地址
FROM
	member
1
2
3
4
5
6
7
8
9
10

# 约束

约束是作用与表中字段上的规则,用于限制存储在表中的数据。目的是为了保证数据库中数据的正确、有效性和完整性。

约束 关键字 描述
非空约束 NOT NULL 限制该字段的数据不能为 NULL
唯一约束 UNIQUE 保证该字段的所有数据都是唯一、不重复的
主键约束 PRIMARY KEY 主键是一行数据的唯一标识,要求非空且唯一
默认约束 DEFAULE 保存数据时,如果未指定该字段的值,则采用默认值
外键约束 FOREIGN KEY 用来让两张表的数据之间建立连接,保证数据的一致性和完整性
检查约束(v8.0.16 之后) CHECK 保证字段值满足某个条件

注意:约束作用于表中的字段上,可以在创建/修改表的时候添加约束。

# 事务

事务就是一组操作的集合,它是一个不可分割的单位,事务会把所有操作当做一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。

MySQL 的事务默认是自动提交的,也就说,当执行一条 DML 语句,MySQL 会立即隐式的提交事务。

# 四大特性

MySQL 的事务满足 ACID 特性:

  • 原子性 Atomicity,事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
  • 一致性 Consistency,事务完成时,必须使所有的数据都保持一致状态。
  • 隔离性 Isolation,数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
  • 持久性 Durability,事务一旦提交或回滚,它对数据库中数据的改变就是永久的。

# 操作

  • 查看事务提交方式 SELECT @@autocommit;
  • 设置事务提交方式 SELECT @@autocommit = 0;
  • 开启事务 START TRANSACTIONBEGIN
  • 提交事务 COMMIT;
  • 回滚事务 ROLLBACK;

# 隔离级别

MySQL 中事务的隔离级别一共分为 4 种,隔离级别由低到高依次为:

  1. 读未提交 READ UNCOMMITED,所有事务都可以看到其它事务未提交的数据。
    • 可能发生 脏读,很少使用。
    • 因为可以读取到其他事务中未提交的数据,而未提交的数据可能会发生回滚,因此我们把该级别读取到的数据称之为脏数据,把这个问题称之为脏读。
  2. 读已提交 READ COMMITED,一个事务提交后,它修改的数据才会被其它事务看到。
    • 可能发生 不可重复读
  3. 可重复读 REPEATABLE READ,一个事务执行过程中看到的数据,总是和这个事务开启时看到的数据一致。// MySQL default
    • 可能发生 幻读。InnoDB 通过 MVCC 解决了幻读。
  4. 可串行化 SERIALIZABLE,按照顺序执行事务
    • 解决 幻读。最高隔离级别,效率最低。
隔离级别 脏读 不可重复读 幻读
读未提交 Y Y Y
读已提交 - Y Y
可重复读 - - Y
可串行化 - - -

注:Y 表示可能发生,- 表示不会发生。

# 事务问题

主要有 3 种问题:

  • 脏读,一个事务读取到其它事务还未提交的数据(未提交的数据可能会发生回滚)。
  • 不可重复读,当一个事务 A 开启后,查询 user1 后,事务 B 修改了 user1 的数据并提交了,然后事务 A 的第 2 步有查询了 user1,这时候对于事务 A 来说,读取到的 user1 数据变化了,这种现象就是不可重复读。
  • 幻读,事务 A 中第一步查询 user1 不存在,事务 B 创建出来 user1,事务 A 第一步中查询 user1 不存在则执行插入操作,但是插入失败,查询 user1 也是不存在(解决不可重复读后,事务读取的数据总和事务开启前一致,所以事务 B 插入后,事务 A 也读取不到的),这种现象就是幻读。即,我查询没有啊,怎么插入的时候,又有了?

# 讨论区

由于评论过多会影响页面最下方的导航,故将评论区做默认折叠处理。

点击查看评论区内容,渴望您的宝贵建议~
Last Updated: 7/24/2023, 1:44:25 PM