若文章内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系博主删除。

写这篇博客旨在制作笔记,方便个人在线阅览,巩固知识。
博客的内容主要来自视频内容和资料中提供的学习笔记。
关于视频中出现的案例我则记录在了这篇博客里:《MySQL 学习笔记①_案例记录》
net start mysql80
net stop mysql80
上述的 mysql80 是我们在安装 MySQL 时,默认指定的 mysql 的系统服务名,不是固定的。若未改动,默认是 mysql80。
mysql [-h 127.0.0.1] [-P 3306] -u root -p
-h:MySQL 服务所在的主机IP-P:MySQL 服务端口号, 默认 3306-u:MySQL 数据库用户名-p:MySQL 数据库用户名对应的密码| 分类 | 全称 | 说明 |
|---|---|---|
| DDL | Data Definition Language | 数据定义语言,用来定义数据库对象(数据库、表、字段) |
| DML | Data Manipulation Language | 数据操作语言,用来对数据库表中的数据进行增删改 |
| DQL | Data Query Language | 数据查询语言,用来查询数据库中表的记录 |
| DCL | Data Contorl Language | 数据控制语言,用来创建数据库用户、控制数据库的控制权限 |
SHOW DATABASES;
SELECT DATABASE();
CREATE DATABASE [IF NOT EXISTS] 数据库名 [DEFAULT CHARSET 字符集] [COLLATE 排序规则];
DROP DATABASE [IF EXISTS] 数据库名;
USE 数据库名;
SHOW TABLES;
DESC 表名;
SHOW CREATE TABLE 表名;
CREATE TABLE 表名(
字段1 字段1类型 [COMMENT 字段1注释],
字段2 字段2类型 [COMMENT 字段2注释],
字段3 字段3类型 [COMMENT 字段3注释],
...
字段n 字段n类型 [COMMENT 字段n注释]
)[ COMMENT 表注释 ];
ALTER TABLE 表名 ADD 字段名 类型(长度) [COMMENT 注释] [约束];
例:ALTER TABLE emp ADD nickname varchar(20) COMMENT '昵称';
ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度);
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型(长度) [COMMENT 注释] [约束];
例:将 emp 表的 nickname 字段修改为 username,类型为 varchar(30)
ALTER TABLE emp CHANGE nickname username varchar(30) COMMENT '昵称';ALTER TABLE 表名 RENAME TO 新表名
ALTER TABLE 表名 DROP 字段名;
DROP TABLE [IF EXISTS] 表名;
TRUNCATE TABLE 表名;
INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (值1, 值2, ...);
INSERT INTO 表名 VALUES (值1, 值2, ...);
INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (值1, 值2, ...), (值1, 值2, ...), (值1, 值2, ...);
INSERT INTO 表名 VALUES (值1, 值2, ...), (值1, 值2, ...), (值1, 值2, ...);
UPDATE 表名 SET 字段名1 = 值1, 字段名2 = 值2, ... [ WHERE 条件 ];
例:UPDATE emp SET name = 'Jack' WHERE id = 1;
DELETE FROM 表名 [WHERE 条件];
SELECT
字段列表
FROM
表名字段
WHERE
条件列表
GROUP BY
分组字段列表
HAVING
分组后的条件列表
ORDER BY
排序字段列表
LIMIT
分页参数
SELECT 字段1, 字段2, 字段3, ... FROM 表名;
SELECT * FROM 表名;
SELECT 字段1 [ AS 别名1 ], 字段2 [ AS 别名2 ], 字段3 [ AS 别名3 ], ... FROM 表名;
上方代码块中的 as 可省略
SELECT 字段1 [ 别名1 ], 字段2 [ 别名2 ], 字段3 [ 别名3 ], ... FROM 表名;
SELECT DISTINCT 字段列表 FROM 表名;
SELECT * FROM 表名 WHERE name LIKE '/_张三' ESCAPE '/'
/ 之后的 _ 不作为通配符
SELECT 字段列表 FROM 表名 WHERE 条件列表;
| 比较运算符 | 功能 |
|---|---|
| > | 大于 |
| >= | 大于等于 |
| < | 小于 |
| <= | 小于等于 |
| = | 等于 |
| <> 或 != | 不等于 |
| BETWEEN … AND … | 在某个范围内(含最小、最大值) |
| IN(…) | 在in之后的列表中的值,多选一 |
| LIKE 占位符 | 模糊匹配( _ 匹配单个字符,% 匹配任意个字符 ) |
| IS NULL | 是 NULL |
| 逻辑运算符 | 功能 |
|---|---|
| AND 或 && | 并且(多个条件同时成立) |
| OR 或 || | 或者(多个条件任意一个成立) |
| NOT 或 ! | 非,不是 |
将一列数据作为一个整体,进行纵向计算 。
常见聚合函数
| 函数 | 功能 |
|---|---|
| count | 统计数量 |
| max | 最大值 |
| min | 最小值 |
| avg | 平均值 |
| sum | 求和 |
SELECT 聚合函数(字段列表) FROM 表名;
SELECT count(id) from employee where workaddress = "广东省";SELECT 字段列表 FROM 表名 [ WHERE 条件 ] GROUP BY 分组字段名 [ HAVING 分组后的过滤条件 ];
group by columnA, columnB-- 根据性别分组,统计男性和女性数量(只显示分组数量,不显示哪个是男哪个是女)
select count(*) from employee group by gender;
-- 根据性别分组,统计男性和女性数量
select gender, count(*) from employee group by gender;
-- 根据性别分组,统计男性和女性的平均年龄
select gender, avg(age) from employee group by gender;
-- 年龄小于 45,并根据工作地址分组
select workaddress, count(*) from employee where age < 45 group by workaddress;
-- 年龄小于 45,并根据工作地址分组,获取员工数量大于等于 3 的工作地址
select workaddress, count(*) address_count from employee where age < 45 group by workaddress having address_count >= 3;
SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1, 字段2 排序方式2;
SELECT 字段列表 FROM 表名 LIMIT 起始索引, 查询记录数;

USE mysql;
SELECT * FROM user;
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码';
DROP USER '用户名'@'主机名';

MySQL 中定义了很多种权限,但是常用的就以下几种
| 权限 | 说明 |
|---|---|
| ALL,ALL PRIVILEGES | 所有权限 |
| SELECT | 查询数据 |
| INSERT | 插入数据 |
| UPDATE | 修改数据 |
| DELETE | 删除数据 |
| ALTER | 修改表 |
| DROP | 删除数据库/表/视图 |
| CREATE | 创建数据库/表 |
上述只是简单罗列了常见的几种权限描述,其他权限描述及含义,可以直接参考官方文档。
SHOW GRANTS FOR '用户名'@'主机名' ;
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';
REVOKE 权限列表 ON 数据库名.表名 FROM '用户名'@'主机名';
常用函数
| 函数 | 功能 |
|---|---|
| CONCAT(s1, s2, …, sn) | 字符串拼接,将 s1, s2, …, sn 拼接成一个字符串 |
| LOWER(str) | 将字符串全部转为小写 |
| UPPER(str) | 将字符串全部转为大写 |
| LPAD(str, n, pad) | 左填充,用字符串 pad 对 str 的左边进行填充,达到 n 个字符串长度 |
| RPAD(str, n, pad) | 右填充,用字符串 pad 对 str 的右边进行填充,达到 n 个字符串长度 |
| TRIM(str) | 去掉字符串头部和尾部的空格 |
| SUBSTRING(str, start, len) | 返回从字符串 str 从 start 位置起的 len 个长度的字符串 |
-- 拼接
SELECT CONCAT('Hello', 'World');
-- 小写
SELECT LOWER('Hello');
-- 大写
SELECT UPPER('Hello');
-- 左填充
SELECT LPAD('01', 5, '-');
-- 右填充
SELECT RPAD('01', 5, '-');
-- 去除首尾的空格
SELECT TRIM(' Hello World ');
-- 切片(注意,该函数的起始索引为 1)
SELECT SUBSTRING('Hello World', 1, 5);
常见函数
| 函数 | 功能 |
|---|---|
| CEIL(x) | 向上取整 |
| FLOOR(x) | 向下取整 |
| MOD(x, y) | 返回 x/y 的模 |
| RAND() | 返回 0~1 内的随机数 |
| ROUND(x, y) | 求参数 x 的四舍五入值,保留 y 位小数 |
-- 向上取整
SELECT CEIL(1.1);
-- 向下取整
SELECT FLOOR(1.9);
-- 取模
SELECT MOD(7,4);
-- 获取随机数
SELECT RAND();
-- 四舍五入
SELECT ROUND(2.344,2);
常用函数
| 函数 | 功能 |
|---|---|
| CURDATE() | 返回当前日期 |
| CURTIME() | 返回当前时间 |
| NOW() | 返回当前日期和时间 |
| YEAR(date) | 获取指定 date 的年份 |
| MONTH(date) | 获取指定 date 的月份 |
| DAY(date) | 获取指定 date 的日期 |
| DATE_ADD(date, INTERVAL expr type) | 返回一个日期/时间值加上一个时间间隔 expr 后的时间值 |
| DATEDIFF(date1, date2) | 返回起始时间 date1 和结束时间 date2 之间的天数 |
SELECT CURDATE();
SELECT CURTIME();
SELECT NOW();
SELECT YEAR(NOW());
SELECT MONTH(NOW());
SELECT DAY(NOW());
SELECT DATE_ADD(NOW(), INTERVAL 70 YEAR );
SELECT DATEDIFF('2021-10-01', '2021-12-01');
常用函数
| 函数 | 功能 |
|---|---|
| IF(value, t, f) | 如果 value 为 true,则返回 t,否则返回 f |
| IFNULL(value1, value2) | 如果 value1 不为空,返回 value1,否则返回 value2 |
| CASE WHEN [ val1 ] THEN [ res1 ] … ELSE [ default ] END | 如果 val1 为 true,返回 res1,… 否则返回 default 默认值 |
| CASE [ expr ] WHEN [ val1 ] THEN [ res1 ] … ELSE [ default ] END | 如果 expr 的值等于 val1,返回 res1,… 否则返回 default 默认值 |
SELECT
name,
(CASE WHEN age > 30 THEN '中年' ELSE '青年' END) AS '青年/中年'
FROM employee;
select
name,
(case workaddress when '北京市' then '一线城市' when '上海市' then '一线城市' else '二线城市' end) as '工作地址'
from employee;
概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据。
目的:保证数据库中数据的正确、有效性和完整性。
| 约束 | 描述 | 关键字 |
|---|---|---|
| 非空约束 | 限制该字段的数据不能为 null | NOT NULL |
| 唯一约束 | 保证该字段的所有数据都是唯一、不重复的 | UNIQUE |
| 主键约束 | 主键是一行数据的唯一标识,要求非空且唯一 | PRIMARY KEY |
| 默认约束 | 保存数据时,如果未指定该字段的值,则采用默认值 | DEFAULT |
| 检查约束(8.0.1 版本后) | 保证字段值满足某一个条件 | CHECK |
| 外键约束 | 用来让两张图的数据之间建立连接,保证数据的一致性和完整性 | FOREIGN KEY |
| 约束条件 | 关键字 |
|---|---|
| 主键 | PRIMARY KEY |
| 自动增长 | AUTO_INCREMENT |
| 不为空 | NOT NULL |
| 唯一 | UNIQUE |
| 逻辑条件 | CHECK |
| 默认值 | DEFAULT |
create table user(
id int primary key auto_increment,
name varchar(10) not null unique,
age int check(age > 0 and age < 120),
status char(1) default '1',
gender char(1)
);
外键:用来让两张表的数据之间建立连接,从而保证数据的一致性和完整性。
CREATE TABLE 表名(
字段名 字段类型,
...
[CONSTRAINT] [外键名称] FOREIGN KEY(外键字段名) REFERENCES 主表(主表列名)
);
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名) REFERENCES 主表(主表列名);
alter table emp add constraint fk_emp_dept_id foreign key(dept_id) references dept(id);ALTER TABLE 表名 DROP FOREIGN KEY 外键名;
| 行为 | 说明 |
|---|---|
| NO ACTION | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新(与 RESTRICT 一致) |
| RESTRICT | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新(与 NO ACTION 一致) |
| CASCADE | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则也删除/更新外键在子表中的记录 |
| SET NULL | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则设置子表中该外键值为 null(要求该外键允许为 null) |
| SET DEFAULT | 父表有变更时,子表将外键设为一个默认值(Innodb 不支持) |
ALTER TABLE 表名
ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段) REFERENCES 主表名(主表字段名)
ON UPDATE 行为
ON DELETE 行为;
多表关系
一对多

多对多

一对一

多表查询就是指从多张表中查询数据。
原来查询单表数据,执行的 SQL 形式为:select * from emp;
那么我们要执行多表查询,就只需要使用逗号分隔多张表即可,如:select * from emp , dept;

如上所示,我们看到查询结果中包含了大量的结果集,总共 102 条记录。(dept 表共 6 条记录,emp 表共17条记录。)
这其实就是员工表 emp 所有的记录(17)与 部门表 dept 所有记录(6)的所有组合情况,这种现象称之为笛卡尔积。
笛卡尔积:笛卡尔乘积是指在数学中,两个集合(A 集合 和 B 集合)的所有组合情况。

在多表查询中,我们是需要消除无效的笛卡尔积的,只保留两张表关联部分的数据。

在 SQL 语句中,如何来去除无效的笛卡尔积呢? 我们可以给多表查询加上连接查询的条件即可。
SELECT * FROM emp , dept WHERE emp.dept_id = dept.id;

连接查询
子查询:嵌套在其他查询中的查询
内连接查询的是两张表交集部分的数据。(也就是绿色部分的数据)
内连接的语法分为两种: 隐式内连接、显式内连接。

SELECT 字段列表 FROM 表1 , 表2 WHERE 条件 ... ;
SELECT 字段列表 FROM 表1 [ INNER ] JOIN 表2 ON 连接条件 ... ;
SELECT emp.name , dept.name FROM emp , dept WHERE emp.dept_id = dept.id;
-- 为每一张表起别名,简化 SQL 编写
SELECT e.name, d.name FROM emp e , dept d WHERE e.dept_id = d.id;
SELECT e.name, d.name FROM emp e INNER JOIN dept d ON e.dept_id = d.id;
-- 为每一张表起别名,简化 SQL 编写
SELECT e.name, d.name FROM emp e JOIN dept d ON e.dept_id = d.id;
表的别名
tablea as 别名1, tableb as 别名2;
tablea 别名1, tableb 别名2;
注意事项:一旦为表起了别名,就不能再使用表名来指定对应的字段了,此时只能够使用别名来指定字段。
左外连接相当于查询表1(左表)的所有数据,当然也包含表1和表2交集部分的数据。
SELECT 字段列表 FROM 表1 LEFT [ OUTER ] JOIN 表2 ON 条件 ... ;
右外连接相当于查询表2(右表)的所有数据,当然也包含表1和表2交集部分的数据。
SELECT 字段列表 FROM 表1 RIGHT [ OUTER ] JOIN 表2 ON 条件 ... ;
即 RIGHT 指出的是 OUTER JOIN 右边的表,lEFT 指出的是 OUTER JOIN 左边的表。
自连接查询,顾名思义,就是自己连接自己,也就是把一张表连接查询多次。
SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件 ... ;
对于自连接查询,可以是内连接查询,也可以是外连接查询。
对于 union 查询,就是把多次查询的结果合并起来,形成一个新的查询结果集。
SELECT 字段列表 FROM 表A ...
UNION [ ALL ]
SELECT 字段列表 FROM 表B ....;

SQL 语句中嵌套 SELECT 语句,称为嵌套查询,又称子查询。
SELECT * FROM t1 WHERE column1 = ( SELECT column1 FROM t2 );
子查询外部的语句可以是 INSERT / UPDATE / DELETE / SELECT 的任何一个。
根据子查询结果可以分为:
根据子查询位置可分为:
子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式,这种子查询称为标量子查询。
常用的操作符:=、<>、>、>=、<、<=
-- 查询销售部所有员工
select id from dept where name = '销售部';
-- 根据销售部部门 ID,查询员工信息
select * from employee where dept = 4;
-- 合并(子查询)
select * from employee where dept = (select id from dept where name = '销售部');
-- 查询入职时间在 xxx 入职时间之后的员工信息
select * from employee where entrydate > (select entrydate from employee where name = 'xxx');
子查询返回的结果是一列(可以是多行),这种子查询称为列子查询。
常用的操作符:IN 、NOT IN、 ANY 、SOME 、 ALL
常用操作符
| 操作符 | 描述 |
|---|---|
| IN | 在指定的集合范围内,多选一 |
| NOT IN | 不在指定的集合范围内 |
| ANY | 子查询返回列表中,有任意一个满足即可 |
| SOME | 与 ANY 等同,使用 SOME 的地方都可以使用 ANY |
| ALL | 子查询返回列表的所有值都必须满足 |
例:查询销售部和市场部的所有员工信息
select * from employee where dept in (select id from dept where name = '销售部' or name = '市场部');
例:查询比财务部所有人工资都高的员工信息
select * from employee where salary > all(select salary from employee where dept = (select id from dept where name = '财务部'));
例:查询比研发部任意一人工资高的员工信息
select * from employee where salary > any (select salary from employee where dept = (select id from dept where name = '研发部'));
子查询返回的结果是一行(可以是多列),这种子查询称为行子查询。
常用的操作符:=、<>、IN、NOT IN
例:查询与 xxx 的薪资及直属领导相同的员工信息
select * from employee where (salary, manager) = (12500, 1);
select * from employee where (salary, manager) = (select salary, manager from employee where name = 'xxx');
返回的结果是多行多列
常用操作符:IN
例:查询与 xxx1,xxx2 的职位和薪资相同的员工
select * from employee where (job, salary) in (select job, salary from employee where name = 'xxx1' or name = 'xxx2');
例:查询入职日期是 2006-01-01 之后的员工,及其部门信息
select e.*, d.* from (select * from employee where entrydate > '2006-01-01') as e left join dept as d on e.dept = d.id;
事务是一组操作的集合,它是一个不可分割的工作单位。
事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求。即这些操作要么同时成功,要么同时失败。
-- 1. 查询张三余额
SELECT * FROM account WHERE NAME = '张三';
-- 2. 张三的余额减少 1000
UPDATE account SET money = money - 1000 WHERE NAME = '张三';
-- 3. 李四的余额增加 1000
UPDATE account SET money = money + 1000 WHERE NAME = '李四';

-- 1. 查询张三余额
select * from account where name = '张三';
-- 2. 张三的余额减少 1000
update account set money = money - 1000 where name = '张三';
出错啦...
-- 3. 李四的余额增加 1000
update account set money = money + 1000 where name = '李四';

SELECT @@autocommit ;
SET @@autocommit = 0 ;
START TRANSACTION
BEGIN TRANSACTION;
COMMIT;
ROLLBACK;
以下是事务的四大特性,简称 ACID。
| 问题 | 描述 |
|---|---|
| 脏读 | 一个事务读到另一个事务还没提交的数据 |
| 不可重复读 | 一个事务先后读取同一条记录,但两次读取的数据不同 |
| 幻读 | 一个事务按照条件查询数据时,没有对应的数据行,但是再插入数据时,又发现这行数据已经存在 |
这三个问题的详细演示:基础-事务-并发事务问题(视频 P55 里讲的很清楚,这个视频最好看完)
比如


事务 A 两次读取同一条记录,但是读取到的数据却是不一样的

| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| Read uncommitted | √ | √ | √ |
| Read committed | × | √ | √ |
| Repeatable Read(默认) | × | × | √ |
| Serializable | × | × | × |
SELECT @@TRANSACTION_ISOLATION;
SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE };
SESSION 是会话级别,表示只针对当前会话有效,GLOBAL 表示对所有会话有效