资料来源:https://heuqqdmbyk.feishu.cn/wiki/space/7413668442156498972?ccm_open_type=lark_wiki_spaceLink&open_tab_from=wiki_home

数据库

数据库:DataBase(DB),是存储和管理数据的仓库

数据库管理系统:DataBase Management System(DBMS),操纵和管理数据库的大型软件

SQL:Structured Query Language,操作关系型数据库的编程语言,定义了一套操作关系型数据库统一标准

MySQL

教程来自:05-Web后端基础(数据库) - 飞书云文档

  1. 将数据库软件压缩包解压

01

  1. 将软件文件夹中的bin文件添加到环境变量中
02
  1. 以管理员身份打开CMD,并依次输入以下命令:
1
2
3
4
5
mysqld --initialize-insecure
mysqld -install
net start mysql
mysqladmin -u root password 1234
mysql -uroot -p1234
  1. 登录参数:
1
mysql -u用户名 -p密码 -h要连接的mysql服务器的ip地址(默认127.0.0.1) -P端口号(默认3306)

MySQL数据模型

  • 关系型数据库:建立在关系模型基础上,由多张相互连接的二维表组成的数据库
  • 特点:
    • 使用表存储数据,格式统一,便于维护
    • 使用SQL语言操作,标准统一,使用方便,可用于复杂查询

创建数据库命令:

1
create database xxxx;

SQL

  • SQL:一门操作关系型数据库的编程语言,定义操作所有关系型数据库的统一标准
  • 分类:
分类 全称 说明
DDL Data Definition Language 数据定义语言,用来定义数据库对象(数据库,表,字段)
DML Data Manipulation Language 数据操作语言,用来对数据库表中的数据进行增删改
DQL Data Query Language 数据查询语言,用来查询数据库表的记录
DCL Data Control Language 数据控制语言,用来创建数据库用户、控制数据库的访问权限

DDL

库操作

  • 操作语法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
--查询所有数据库(注意复数形式)
show databases;

--查询当前数据库(注意括号)
select database();

--使用/切换数据库
use 数据库名;

--创建数据库(括号内表示可选属性,创建数据库默认字符集就是utf8mb4)
create database [if not exists] 数据库名 [default charset utf8mb4];

--删除数据库
drop database [if exists] 数据库名;

表操作

  • 创建表的语法:
1
2
3
4
5
create table tablename(
字段1 字段类型 [约束] [comment 字段1注释],
......
字段2 字段类型 [约束] [comment 字段2注释]
)[comment 表注释];

案例说明:

1
2
3
4
5
6
7
create table user(
id int comment 'ID,唯一标识',
username varchar(50) comment '用户名,长度限制50',
name varchar(10) comment '姓名,长度限制10',
age int comment '年龄',
gender char(1) comment '性别'
) comment '用户信息表';

最终结构如下:

id username name age gender
约束
  • 约束:约束时作用于表中字段上的规则,用于限制存储在表中的数据
  • 目的:保证数据库中数据的正确性、有效性和完整性

常见约束如下:

约束 描述 关键字
非空约束 限制该字段值不能为null not null
唯一约束 保证字段的所有数据都是唯一、不重复的 unique
主键约束 主键是一行数据的唯一表示,要求非空且唯一 primary key
默认约束 保存数据时,如果未指定该字段值,则采用默认值 default
外键约束 让两张表的数据建立连接,保证数据的一致性和完整性 foreign key

将之前的案例进行优化:

1
2
3
4
5
6
7
create table user(
id int primary key comment 'ID,唯一标识',
username varchar(50) not null unique comment '用户名,长度限制50',
name varchar(10) not null comment '姓名,长度限制10',
age int comment '年龄',
gender char(1) default '男' comment '性别'
) comment '用户信息表';

想要让主键自动增长,输入auto_increment即可

1
id int primary key auto_increment comment 'ID,唯一标识'
数据类型
数值类型
数据类型 描述
TINYINT 非常小的整数(-128 到 127)
SMALLINT 小整数(-32,768 到 32,767)
MEDIUMINT 中等大小的整数(-8,388,608 到 8,388,607)
INT 普通整数(-2,147,483,648 到 2,147,483,647)
BIGINT 大整数(-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807)
FLOAT 单精度浮点数
DOUBLE 双精度浮点数
DECIMAL 固定小数点数
字符串类型
数据类型 描述
CHAR 定长字符串
VARCHAR 变长字符串
TINYTEXT 非常小的文本
TEXT 小文本
MEDIUMTEXT 中等大小的文本
LONGTEXT 大文本
BINARY 定长二进制数据
VARBINARY 变长二进制数据
TINYBLOB 非常小的BLOB数据
BLOB 小BLOB数据
MEDIUMBLOB 中等大小的BLOB数据
LONGBLOB 大BLOB数据
ENUM 枚举类型
SET 集合类型
日期和时间类型
数据类型 描述
DATE 日期值(YYYY-MM-DD)
TIME 时间值(HH:MM:SS)
DATETIME 日期和时间值(YYYY-MM-DD HH:MM:SS)
TIMESTAMP 时间戳(YYYY-MM-DD HH:MM:SS),存储从1970年1月1日以来的秒数
YEAR 年份值(YYYY)
空间数据类型(Spatial Data Types)
数据类型 描述
GEOMETRY 几何数据的通用类型
POINT 一个点
LINESTRING 一条线
POLYGON 多边形
MULTIPOINT 多个点
MULTILINESTRING 多条线
MULTIPOLYGON 多个多边形
GEOMETRYCOLLECTION 几何数据集合
查询、修改、删除表
  • 表结构的查询、修改、删除相关语法如下:
1
2
3
4
5
6
7
8
9
10
show tables;	-- 查询当前数据库的所有表
desc 表明; -- 查询表结构
show create table 表名; -- 创建表
alter table 表名 add 字段名 类型(长度) [comment 注释] [约束]; -- 添加字段
alter table 表名 modify 字段名 新数据类型(长度); -- 修改字段类型
alter table 表名 change 旧字段名 新字段名 类型(长度) [comment 注释] [约束]; -- 修改字段名与字段类型
alter table 表名 drop column 字段名; -- 删除字段
alter table 表名 rename to 新表名; -- 修改表名

drop table [if exists] 表名; -- 删除表

DML

  • DML英文全称是Data Manipulation Language(数据操作语言),用来对数据库中表的数据记录进行增、删、改操作
  1. 添加数据(INSERT)
  2. 修改数据(UPDATE)
  3. 删除数据(DELETE)

添加数据——Insert

1
2
3
4
5
6
7
8
9
10
11
-- 指定字段添加数据
insert into 表名(字段名1, 字段名2) values (值1, 值2);

-- 全部字段添加数据
insert into 表名 values (值1, 值2, ...);

-- 批量添加数据(指定字段)
insert into 表名 (字段名1, 字段名2) values (值1, 值2),(值1, 值2);

-- 批量添加数据(全部字段)
insert into 表名 values (值1, 值2, ...), (值1, 值2, ...);

修改数据——update

1
2
-- 修改数据
update 表名 set 字段名1 =1 , 字段名2 =2 , ... [where 条件];

注意:修改语句的条件可以有,也可以没有,如果没有条件,则会修改整张表的所有数据

删除数据——delete

1
2
-- 删除数据
delete from 表名 [where 条件];

注意:

  1. DELETE 语句的条件可以有,也可以没有,如果没有条件,则删除整张表的所有数据
  2. DELETE 语句不能删除某一个字段的值(如果要操作,可以使用update,将该字段值设为NULL)

DQL

  • DQL英文全称是Data Query Language(数据查询语言),用来查询数据库表中的记录
  • 关键字:Select

完整的DQL语句语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
select
字段列表
from
表名列表
where
条件列表
group by
分组字段列表
having
分组后条件列表
order by
排序字段列表
limit
分页参数
  • 基本查询:select ... from ...
  • 条件查询:where
  • 分组查询:group by
  • 排序查询:order by
  • 分页查询:limit

基本查询

1
2
3
4
5
6
7
8
9
10
11
12
-- 查询多个字段
select 字段1,字段2,字段3 from 表名;

-- 查询所有字段(通配符)
select * from 表名;

-- 为查询字段设置别名,as关键字可以省略
select 字段1 [as 别名1], 字段2 [as 别名2] from 表名;
select 字段1 别名1,字段2 别名2 from 表名;

-- 去除重复记录
select distinct 字段列表 from 表名;

条件查询

1
2
-- 条件查询
select 字段列表 from 表名 where 条件列表;

条件列表中可以使用比较运算符和逻辑运算符

比较运算符 功能
> 大于
>= 大于等于
< 小于
<= 小于等于
= 等于
<> 或 != 不等于
between … and … 在某个范围之内(含最小值,最大值)
in(…) 在in之后的列表中的值,多选一
like 占位符 模糊匹配(_匹配单个字符, %匹配任意个字符)
is null 是null值(非空值 is not null)
逻辑运算符 功能
and 或 && 并且(多个条件同时成立)
or 或 || 或者(多个条件任意一个成立)
not 或 ! 非 , 不是

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SELECT * FROM xxx WHERE 字段名 = xxx;
SELECT * FROM xxx WHERE 字段名 <> xxx; -- 不等于
SELECT * FROM xxx WHERE 字段名 > xxx;
SELECT * FROM xxx WHERE 字段名 >= xxx;
SELECT * FROM xxx WHERE 字段名 < xxx;
SELECT * FROM xxx WHERE 字段名 <= xxx;
SELECT * FROM xxx WHERE 字段名 BETWEEN xxx AND xxx;
SELECT * FROM xxx WHERE 字段名 IN (xxx, xxx, xxx);
SELECT * FROM xxx WHERE 字段名 LIKE 'xxx%'; -- 以xxx开头
SELECT * FROM xxx WHERE 字段名 LIKE '%xxx'; -- 以xxx结尾
SELECT * FROM xxx WHERE 字段名 LIKE '%xxx%'; -- 包含xxx
SELECT * FROM xxx WHERE 字段名 NOT LIKE 'xxx%'; -- 不以xxx开头
SELECT * FROM xxx WHERE 字段名 = xxx AND 字段名2 = xxx;
SELECT * FROM xxx WHERE 字段名 = xxx OR 字段名2 = xxx;
SELECT * FROM xxx WHERE 字段名 = xxx AND (字段名2 = xxx OR 字段名3 = xxx);
SELECT * FROM xxx WHERE NOT (字段名 = xxx);
SELECT * FROM xxx WHERE 字段名 IS NULL;
SELECT * FROM xxx WHERE 字段名 IS NOT NULL;
SELECT * FROM xxx WHERE (字段名 = xxx OR 字段名2 = xxx) AND 字段名3 BETWEEN xxx AND xxx;

分组查询

聚合函数:将一列数据作为一个整体,进行纵向计算

函数 功能
count 统计数量(NULL值不统计)
max 最大值
min 最小值
avg 平均值
sum 求和
1
2
3
4
5
6
7
SELECT COUNT(*) FROM 表名;
SELECT COUNT(字段名) FROM 表名 WHERE 条件;
SELECT SUM(字段名) FROM 表名 WHERE 条件;
SELECT AVG(字段名) FROM 表名 WHERE 条件;
SELECT AVG(字段名) FROM 表名 WHERE 条件;
SELECT MIN(字段名) FROM 表名 WHERE 条件;
SELECT MAX(字段名) FROM 表名 WHERE 条件;
1
2
--分组查询
select 字段列表 from 表名 [where 条件列表] group by 分组字段名 [having 分组后过滤条件]
  • where与having的区别:
    1. 执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤
    2. 判断条件不同:where不能对聚合函数进行判断,而having可以

单独使用group by:

1
2
SELECT 字段名, COUNT(*) FROM 表名 GROUP BY 字段名;
SELECT 字段名, SUM(字段名2) FROM 表名 GROUP BY 字段名;

结合having使用:

1
2
SELECT 字段名, COUNT(*) FROM 表名 GROUP BY 字段名 HAVING COUNT(*) > 1;
SELECT 字段名, SUM(字段名2) FROM 表名 GROUP BY 字段名 HAVING SUM(字段名2) > 100;

实际案例:

1
select gender, count(*) from emp group by gender;

结果:

gender count(*)
Male 45
Female 35
Other 5

解释:

  1. SELECT gender, count(*): 选择gender列,并计算每个性别的员工数量。

  2. FROM emp: 数据来源于emp表。

  3. GROUP BY gender: 按照gender列对数据进行分组。

排序查询

1
2
-- 排序查询
select 字段列表 from 表名 [where 条件列表] [group by 分组字段名 having 分组后过滤条件] order by 排序字段 排序方式
  • 排序方式:升序(asc),降序(desc);默认为升序asc,也就是可以不写采用默认方式

举例:

假设表为:

department total_employees
Sales 5
IT 5
Marketing 3
HR 2
Finance 2
1
2
3
4
5
SELECT department, COUNT(*) AS total_employees
FROM employees
GROUP BY department
HAVING COUNT(*) > 1
ORDER BY total_employees DESC;

结果:

department total_employees
Sales 15
Marketing 12
IT 10
HR 5
Finance 3

说明:

  1. SELECT department, COUNT(*) AS total_employees: 选择department列,并计算每个部门的员工数量,结果列名为total_employees

  2. FROM employees: 数据来源于employees表。

  3. GROUP BY department: 按照department列对数据进行分组。

  4. HAVING COUNT(*) > 1: 过滤分组后的结果,只保留员工总数大于1的部门。

  5. ORDER BY total_employees DESC: 按照total_employees列进行降序排列

分页查询

1
2
-- 排序查询
select 字段 from 表名 [where 条件] [group by 分组字段 having 过滤条件] [order by 排序字段] limit 起始索引,查询记录数;

说明:

  1. 起始索引从0开始
  2. 分页查询是数据库的方言,不同的数据库有不同的实现,MySQL中是LIMIT
  3. 如果起始索引为0,起始索引可以省略,直接简写为 limit 10

举例:

假设表为:

id name department
1 Alice Sales
2 Bob Sales
3 Charlie Marketing
4 David Marketing
5 Eva IT
6 Frank IT
7 Grace IT
8 Hannah HR
9 Ivy HR
10 Jack Finance
11 Kevin Finance
12 Liam Sales
13 Mia Sales
14 Nina Marketing
15 Oliver IT
1
2
3
4
5
6
7
SELECT department, COUNT(*) AS total_employees
FROM employees
WHERE department IS NOT NULL
GROUP BY department
HAVING COUNT(*) > 1
ORDER BY total_employees DESC
LIMIT 0, 3;

结果:

department total_employees
Sales 4
IT 4
Marketing 3

解释:

  1. SELECT department, COUNT(*) AS total_employees:选择 department 列,并计算每个部门的员工总数,结果列名为 total_employees
  2. FROM employees:数据来源于 employees 表。
  3. WHERE department IS NOT NULL:条件是部门不为空。
  4. GROUP BY department:按照 department 列对数据进行分组。
  5. HAVING COUNT(*) > 1:过滤分组后的结果,只保留员工总数大于1的部门。
  6. ORDER BY total_employees DESC:按照员工总数降序排列。
  7. LIMIT 0, 3:限制查询结果的起始索引为0,并显示前3个记录。

多表关系

  • 项目开发中,在进行数据库表结构设计时,会根据业务需求以及业务模块之间的关系,分析并设计表结构。由于业务之间相互关联,所以各个表结构之间也存在着各种联系
  • 多表关系分为三种:
    1. 一对多(多对一)
    2. 一对一
    3. 多对多

一对多(多对一)

  • 场景:部门与员工的关系(一个部门下有多个员工)

  • 实现思路:在数据库表中的一方(子表),添加字段,来关联一的一方的主键

多表问题

  • 问题:当父表删除某个数据后,子表依旧会关联父表被删除的数据,导致数据不完整、不一致
  • 原因:虽然逻辑上,父表与子表关联,但在数据库层面,并未直接建立关联,所以是无法保证数据的一致性和完整性
  • 解决方案:外键约束

外键约束

  • 可以在创建时或表结构创建完成后,为字段添加外键约束
1
2
3
4
5
6
-- 创建表时指定
create table 表名(
字段名 数据类型,
...
[constraint] [外键名称] foreign key (外键字段名) references 主表 (字段名)
);
1
2
-- 建完表后,添加外键
alter table 表名 add constraint 外键名称 foreign key (外键字段名) references 主表 (字段名);

dept:

id name create_time update_time
1 学工部 2023-09-25 09:47:40 2023-09-25 09:47:40
2 教研部 2023-09-25 09:47:40 2023-10-09 15:17:04
3 咨询部2 2023-09-25 09:47:40 2023-11-30 21:26:24
4 就业部 2023-09-25 09:47:40 2023-09-25 09:47:40
5 人事部 2023-09-25 09:47:40 2023-09-25 09:47:40
15 行政部 2023-11-30 20:56:37 2023-11-30 20:56:37

emp:

id username password name gender phone job salary image entry_date dept_id(外键) create_time update_time
1 shinaian 123456 施耐庵 1 13309090001 4 15000 5.png 2000-01-01 2 2023-10-20 16:35:33 2023-11-16 16:11:26
2 songjiang 123456 宋江 1 13309090002 2 8600 01.png 2015-01-01 2 2023-10-20 16:35:33 2023-10-20 16:35:37
3 lujunyi 123456 卢俊义 1 13309090003 2 8900 01.png 2008-05-01 1 2023-10-20 16:35:33 2023-10-20 16:35:39
4 wuyong 123456 吴用 1 13309090004 2 9200 01.png 2007-01-01 1 2023-10-20 16:35:33 2023-10-20 16:35:41
5 gongsunsheng 123456 公孙胜 1 13309090005 2 9500 01.png 2012-12-05 2 2023-10-20 16:35:33 2023-10-20 16:35:43
查看表之间关系

03

物理外键
  • 概念:使用 foreign key 定义外键关联另一张表
  • 缺点:
    1. 影响增删改的效率(需要检查外键关系)
    2. 仅用于单节点数据库,不适用于分布式、集群场景
    3. 容易引发数据库的死锁问题,消耗性能

一对一

案例:用户与身份证信息的关系

关系:一对一关系,多用于单表拆分,将一张表的基础字段放在一张表中,其他字段放在另一张表中,以提升操作效率

实现:在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的(UNIQUE)

tb_user:

id name gender phone degree
1 白眉鹰王 1 18812340001 初中
2 青翼蝠王 1 18812340002 大专
3 金毛狮王 1 18812340003 初中
4 紫衫龙王 2 18812340004 硕士

tb_user_card:

id nationality birthday idcard issued expire_begin expire_end user_id
1 1960-11-06 100000100000100001 朝阳区公安局 2000-06-10 NULL 1
2 1971-11-06 100000100000100002 静安区公安局 2005-06-10 2025-06-10 2
3 1963-11-06 100000100000100003 昌平区公安局 2006-06-10 NULL 3
4 1980-11-06 100000100000100004 海淀区公安局 2008-06-10 2028-06-10 4

多对多

  • 案例:学生与课程的关系
  • 关系:一个学生可以选秀多门课程,一门课程也可以供多个学生选择
  • 实现:建立第三张中间表,中间表至少包含两个外键,分别关联两方主键

tb_student:

id name no
1 张三 200100101
2 李四 200100102
3 王五 200100103
4 赵六 200100104

tb_course:

id name
1 Java
2 PHP
3 MySQL
4 Hadoop

tb_student_course:

id studentid courseid
1 1 1
2 1 2
3 1 3
4 2 1
5 2 4

多表设计案例

  • 需求:emp(1)➡emp_expr(n)

emp_expr:

1
2
3
4
5
6
7
8
9
-- 表:dept(1)➡emp(n) || emp(1)➡emp_expr(n)
create table emp_expr(
id int unsigned primary key auto_increment comment 'ID,主键',
begin date comment '开始时间',
end date comment '结束时间',
company varchar(50) comment '公司名称',
job varchar(50) comment '职位',
emp_id int unsigned comment '关联的员工ID' -- 采用逻辑外键
) comment '工作经历表';

多表查询

  • 多表查询:指从多张表中查询数据

数据准备

dept:

id name create_time update_time
1 学工部 current_timestamp current_timestamp
2 教研部 current_timestamp current_timestamp
3 咨询部 current_timestamp current_timestamp
4 就业部 current_timestamp current_timestamp
5 人事部 current_timestamp current_timestamp

emp:

id username password name gender phone job salary image entry_date dept_id create_time update_time
1 shinaian 123456 施耐庵 男 (1) 13309090001 4 15000 http://…… 2000-01-01 2 2024-10-27 16:35:33 2024-10-27 16:35:35
2 songjiang 123456 宋江 男 (1) 13309090002 2 8600 http://…… 2015-01-01 2 2024-10-27 16:35:33 2024-10-27 16:35:37
3 lujunyi 123456 卢俊义 男 (1) 13309090003 2 8900 http://…… 2008-05-01 2 2024-10-27 16:35:33 2024-10-27 16:35:39
4 wuyong 123456 吴用 男 (1) 13309090004 2 9200 http://…… 2007-01-01 2 2024-10-27 16:35:33 2024-10-27 16:35:41
5 gongsunsheng 123456 公孙胜 男 (1) 13309090005 2 9500 http://…… 2012-12-05 2 2024-10-27 16:35:33 2024-10-27 16:35:43
6 huosanniang 123456 扈三娘 女 (2) 13309090006 3 6500 http://…… 2013-09-05 1 2024-10-27 16:35:33 2024-10-27 16:35:45

多表查询基本SQL语句

1
select * from emp, dept;

如果直接使用以上SQL语句查询,会出现很多无效数据

为了避免出现上述问题,在查询时要附带条件查询

1
select * from emp, dept where emp.dept_id = dept.id;

连接查询

  • 内连接:相当于查询A、B交集部分数据
  • 外连接:
    • 左外连接:查询左表所有数据(包括两张表交集部分数据)
    • 右外连接:查询右表所有数据(包括两张表交集部分数据)
04
内连接

内连接查询的是两张表交集部分的数据。具体语法为:

1
2
3
4
5
-- 1. 隐式内连接(常见)
select 字段列表 from1,表2 where 连接条件 ...;

-- 2. 显示内连接
select 字段列表 from1 [inner] join2 on 连接条件 ...;

案例:

1
2
3
4
5
6
7
8
9
10
11
-- ============================= 内连接 ==========================
-- A. 查询所有员工的ID, 姓名 , 及所属的部门名称 (隐式、显式内连接实现)
select emp.id,emp.name,dept.name from emp,dept where emp.dept_id = dept.id;

select emp.id,emp.name,dept.name from dept inner join emp on emp.dept_id = dept.id;


-- B. 查询 性别为男, 且工资 高于8000 的员工的ID, 姓名, 及所属的部门名称 (隐式、显式内连接实现)
select emp.id,emp.name,dept.name from emp,dept where emp.dept_id = dept.id and emp.gender = 1 and emp.salary > 8000;

select emp.id,emp.name,dept.name from dept inner join emp on emp.dept_id = dept.id where emp.gender = 1 and emp.salary > 8000;
外连接
  • 外连接分为左外连接和右外连接。具体语法为:
1
2
3
4
5
-- 1. 左外连接(常见)
select 字段名称 from1 left [outer] join2 on 连接条件 ...;

-- 2. 右外连接
select 字段列表 from1 right [outer] join2 on 连接条件 ...;

案例:

1
2
3
4
5
6
7
8
9
-- =============================== 外连接 ============================
-- A. 查询员工表 所有 员工的姓名, 和对应的部门名称 (左外连接)
select emp.name, dept.name from emp left outer join dept on dept.id = emp.dept_id;

-- B. 查询部门表 所有 部门的名称, 和对应的员工名称 (右外连接)
select emp.name, dept.name from emp right outer join dept on dept.id = emp.dept_id;

-- C. 查询工资 高于8000 的 所有员工的姓名, 和对应的部门名称 (左外连接)
select emp.name, dept.name from emp left outer join dept on dept.id = emp.dept_id where emp.salary > 8000;
子查询
  • 介绍:SQL语句中嵌套select语句,称为嵌套查询,又称子查询
  • 形式:select * from t1 where column1 = (select column1 from t2 ...);
  • 说明:子查询外部的语句可以是 insert / update / delete / select 的任何一个,最常见的是 select
  • 分类:
    1. 标量子查询:子查询返回的结果为单个值
    2. 列子查询:子查询返回的结果为一列
    3. 行子查询:子查询返回的结果为一行
    4. 表子查询:子查询返回的结果为多行多列
  • 要点:子查询的要点是,先对需求做拆分,明确具体步骤,再逐步编写SQL语句

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
-- ========================= 子查询 ================================
-- 标量子查询
-- A. 查询 最早入职 的员工信息:
-- 1. 获取到最早入职时间
select min(emp.entry_date) from emp; -- 2000-01-01
-- 2. 查询 最早入职 的员工信息
select * from emp where entry_date = '2000-01-01';
-- 3. 结合
select * from emp where entry_date = (select min(emp.entry_date) from emp);


-- B. 查询在 "阮小五" 入职之后入职的员工信息
-- 1. 获取到阮小五入职时间
select emp.entry_date from emp where emp.name = '阮小五'; -- 2015-01-01
-- 2. 查询在 "阮小五" 入职之后入职的员工信息
select * from emp where entry_date > '2015-01-01';
-- 3. 结合
select * from emp where entry_date > (select emp.entry_date from emp where emp.name = '阮小五');

-- 列子查询
-- A. 查询 "教研部" 和 "咨询部" 的所有员工信息
-- 1. 查询"教研部"和"咨询部"的ID
select id from dept where dept.name = '教研部' or dept.name = '咨询部'; -- 3 2
-- 2. 查询指定部门ID的员工信息
select * from emp where emp.dept_id in (2,3);
-- 3. 结合
select * from emp where emp.dept_id in (select id from dept where dept.name = '教研部' or dept.name = '咨询部')

-- 行子查询
-- A. 查询与 "李忠" 的薪资 及 职位都相同的员工信息 ;
-- 1. 查询"李忠" 的薪资以及职位
select emp.salary , emp.job from emp where emp.name = '李忠'; -- 5000 5
-- 2. 查询与 "李忠" 的薪资 及 职位都相同的员工信息
select * from emp where salary = '5000' and job = '5';
-- 3. 结合
select * from emp where salary = (select emp.salary from emp where emp.name = '李忠') and job = (select emp.job from emp where emp.name = '李忠')

-- 表子查询
-- A. 获取每个部门中薪资最高的员工信息
-- 1. 获取每个部门的最高薪资
select dept_id,max(salary) from emp group by dept_id;

-- 2. 查询每个部门中薪资最高的员工信息
select * from emp , (select dept_id,max(salary) as max_sal from emp group by dept_id) as res where emp.dept_id = res.dept_id and emp.salary = res.max_sal;
综合案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
-- 需求:
-- 1. 查询 "教研部" 性别为 男,且在 "2011-05-01" 之后入职的员工信息 。
SELECT *
FROM emp
WHERE gender = 1
AND entry_date > '2011-05-01'
AND dept_id = (
SELECT id
FROM dept
WHERE name = '教研部'
);

-- 2. 查询工资 低于公司平均工资的 且 性别为男 的员工信息 。
SELECT *
FROM emp
WHERE gender = 1
AND salary < (SELECT AVG(salary) FROM emp);


-- 3. 查询部门人数超过 10 人的部门名称 。
select dept.name from dept;
select emp.dept_id from emp group by emp.dept_id;
SELECT name
FROM dept
WHERE id IN (
SELECT dept_id
FROM emp
GROUP BY dept_id
HAVING COUNT(*) > 10
);


-- 4. 查询在 "2010-05-01" 后入职,且薪资高于 10000 的 "教研部" 员工信息,并根据薪资倒序排序。
SELECT *
FROM emp
WHERE entry_date > '2010-05-01'
AND salary > 10000
AND dept_id = (
SELECT id
FROM dept
WHERE name = '教研部'
)
ORDER BY salary DESC;

-- 5. 查询工资 低于本部门平均工资的员工信息 。
SELECT *
FROM emp e1
WHERE salary < (
SELECT AVG(salary)
FROM emp e2
WHERE e1.dept_id = e2.dept_id
);

MySQL图形化工具