11029 字
55 分钟
04:mysql之综合查询

[TOC]

04:mysql之综合查询#

今日工作任务路线图

flowchart LR
subgraph BottomRow[综合查询]
direction LR
A[内连接查询] --> B[外连接查询] --> C[合并查询结果] --> D[嵌套查询]
end

一、工作场景#

在一家中型企业的人力资源管理工作里,会频繁运用 MySQL 综合查询。企业有员工表,包含员工编号、姓名、入职时间等;部门表记录着部门编号、部门名称等;薪资表存有员工编号、薪资数额、发放日期等。

每到季度末,人力部门需要统计各部门员工的平均薪资。这时就会综合查询这三张表。通过员工编号关联员工表和薪资表,再通过部门编号关联员工表和部门表。筛选出本季度发放的薪资数据,按部门分组计算平均薪资。如此,就能清晰了解各部门的人力成本,为后续的预算规划、薪资调整等提供数据支撑。

二、为什么要学综合查询#

在日常工作里,学会 MySQL 综合查询是非常必要的。以员工表、部门表和薪资表为例,单看一张表,能获取的信息有限。员工表只有员工基本信息,部门表只有部门情况,薪资表只有薪资数据。

但当你掌握综合查询,就能将三张表关联起来。比如想知道每个部门的平均薪资,就可以通过员工表关联部门表和薪资表,快速得出结果。还能查询出不同部门入职时间早且薪资高的员工。综合查询让你从多个角度挖掘数据价值,为企业的决策提供准确依据,极大提升工作效率和质量,所以很有学习的必要。

三、内连接查询#

当前任务环节

flowchart LR
subgraph BottomRow[综合查询]
direction LR
A[内连接查询] --> B[外连接查询] --> C[合并查询结果] --> D[嵌套查询]
end
classDef highlight stroke:#f00,stroke-width:2px;
class A highlight;

MySQL 内连接查询是一种常用的表连接方式,用于从多个表中提取相关联的数据。它分为隐式和显式内连接查询,区别在于是否包含 inner【ing呐】 join【载(白话)】 关键字 。只有主表和从表中的数据都满足连接条件时才能被查询出来,不满足则会被忽略 。

例如有员工表和部门表,若要查询每个员工所在部门的信息,可通过员工表中的部门 ID 与部门表中的 ID 匹配连接,获取员工姓名和部门名称等信息。内连接能确保数据准确,适用于查询具有明确关联关系的表 。

使用moershi库下的3张表做今天的查询练习。

  • departments【迪帕踢门特s】:部门表,存储部门信息
  • employees【ing普洛伊s】: 员工表,存储员工信息
  • salary【撒拉瑞】: 工资表,存储工资信息

三张表的关系如果图

INNER【ing呐】 JOIN【载(白话)】 关键字详解#

INNER【ing呐】 JOIN【载(白话)】是SQL中最基础且最重要的连接操作,它通过精确的匹配条件将相关的数据行连接在一起,是构建复杂查询和数据分析的基石。掌握INNER【ing呐】 JOIN【载(白话)】的正确用法对于进行有效的数据处理至关重要。

属性说明
关键字INNER【ing呐】 JOIN【载(白话)】
中文名称内连接
作用返回两个表中满足连接条件的匹配行
语法SELECT【涩莱克特】 列名 FROM【弗乱】 表1 INNER【ing呐】 JOIN【载(白话)】 表2 ON【昂】 连接条件
返回值只返回两个表中连接条件为TRUE的行
等价写法可以省略INNER【ing呐】,直接写JOIN【载(白话)】

语法结构#

基本语法结构

SELECT【涩莱克特】 列名列表 FROM【弗乱】 表1 INNER【ing呐】 JOIN【载(白话)】 表2 ON【昂】 表1.列名 = 表2.列名;
表1 INNER【ing呐】 JOIN【载(白话)】 表2: 是表连接 的核心部分,用于将 1 表和 2 表的数据关联起来。
作用
指定主表和从表:
1 是主表(左表)。
2 是从表(右表)。
定义连接类型:
INNER JOIN 表示内连接,只返回两个表中匹配的记录。
如果 1 表中的某条记录在 2 表中没有匹配的记录(即 employee_id 不匹配),则该记录不会出现在结果中。
配合连接条件:
通常与 ON 子句一起使用(例如 ON employees.employee_id = salary.employee_id ),以指定如何匹配两个表的记录。
ON【昂】 表1.列名 = 表2.列名: 是 连接条件,用于指定 1 表和 2 表之间的关联关系
作用
定义表之间的关联:
它告诉数据库如何将 employees 表中的记录与 salary 表中的记录匹配起来。
只有当 employees.employee_idsalary.employee_id 的值相等时,两条记录才会被关联起来。
确保数据一致性:
通过这个条件,查询只会返回那些在 employees 表和 salary 表中都有对应 employee_id 的记录(如果是 INNER JOIN )。
如果是 LEFT JOIN ,则会返回 employees 表中的所有记录,即使 salary 表中没有匹配的记录(此时 salary 表的字段会显示为 NULL【nò】 )。

完整语法格式

SELECT【涩莱克特】 [表别名1].列名, [表别名2].列名, ...
FROM【弗乱】 表1 [AS] 表别名1
INNER【ing呐】 JOIN【载(白话)】 表2 [AS] 表别名2 ON【昂】 表别名1.连接列 = 表别名2.连接列
[WHERE【威尔】 筛选条件]
[ORDER【欧朵】 BY 排序字段];
示例#

1:基本INNER【ing呐】 JOIN【载(白话)】查询

-- 查询员工及其部门信息
SELECT【涩莱克特】 e.employee【ing普洛伊】_id, e.name, d.dept_name, e.hire_date
FROM【弗乱】 employees【ing普洛伊s】 e
INNER【ing呐】 JOIN【载(白话)】 departments【迪帕踢门特s】 d ON【昂】 e.dept_id = d.dept_id;

查询结果:

employee【ing普洛伊】_idnamedept_namehire_date
1张三技术部2023-01-15
2李四销售部2023-03-20
3王五技术部2023-02-10
4赵六人事部2023-04-05

2:带WHERE【威尔】条件的INNER【ing呐】 JOIN【载(白话)】

-- 只查询技术部的员工
SELECT【涩莱克特】 e.name, d.dept_name, e.hire_date
FROM【弗乱】 employees【ing普洛伊s】 e
INNER【ing呐】 JOIN【载(白话)】 departments【迪帕踢门特s】 d ON【昂】 e.dept_id = d.dept_id
WHERE【威尔】 d.dept_name = '技术部';

查询结果:

namedept_namehire_date
张三技术部2023-01-15
王五技术部2023-02-10

3:多表INNER【ing呐】 JOIN【载(白话)】连接

-- 假设有salary【撒拉瑞】表,三表连接
SELECT【涩莱克特】 e.name, d.dept_name, s.basic【贝斯克】_salary【撒拉瑞】
FROM【弗乱】 employees【ing普洛伊s】 e
INNER【ing呐】 JOIN【载(白话)】 departments【迪帕踢门特s】 d ON【昂】 e.dept_id = d.dept_id
INNER【ing呐】 JOIN【载(白话)】 salary【撒拉瑞】 s ON【昂】 e.employee【ing普洛伊】_id = s.employee【ing普洛伊】_id;
使用场景分析#
场景说明示例
主从表关联查询主表记录的详细信息员工表关联部门表查部门信息
多维度分析结合多个维度的数据进行统计销售数据关联产品表、客户表
数据验证检查两个表的数据一致性验证订单表和库存表的数据匹配
报表生成生成包含多个表数据的综合报表员工考勤关联工资计算
与其他JOIN【载(白话)】类型的对比#
特性INNER【ing呐】 JOINLEFT【列夫特】 JOIN【载(白话)】RIGHT【来特】 JOIN【载(白话)】FULL【fò】 JOIN【载(白话)】
返回结果只返回匹配行左表所有行+匹配行右表所有行+匹配行左右表所有行
NULL【nò】处理排除不匹配行右表不匹配显示NULL【nò】左表不匹配显示NULL【nò】不匹配都显示NULL【nò】
使用频率⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
性能通常最优中等中等较差

最佳实践指南#

  1. 使用表别名提高可读性
-- 推荐写法
SELECT【涩莱克特】 emp.name, dept.dept_name
FROM【弗乱】 employees【ing普洛伊s】 emp
INNER【ing呐】 JOIN【载(白话)】 departments【迪帕踢门特s】 dept ON【昂】 emp.dept_id = dept.dept_id;
-- 不推荐写法
SELECT【涩莱克特】 employees【ing普洛伊s】.name, departments【迪帕踢门特s】.dept_name
FROM【弗乱】 employees【ing普洛伊s】
INNER【ing呐】 JOIN【载(白话)】 departments【迪帕踢门特s】 ON【昂】 employees【ing普洛伊s】.dept_id = departments【迪帕踢门特s】.dept_id;
  1. 明确指定列所属表
-- 避免列名歧义
SELECT【涩莱克特】 e.employee【ing普洛伊】_id, e.name, d.dept_name
FROM【弗乱】 employees【ing普洛伊s】 e
INNER【ing呐】 JOIN【载(白话)】 departments【迪帕踢门特s】 d ON【昂】 e.dept_id = d.dept_id;
  1. 合理使用索引优化性能
-- 确保连接列有索引
CREATE INDEX idx_employees【ing普洛伊s】_dept_id ON【昂】 employees【ing普洛伊s】(dept_id);
CREATE INDEX idx_departments【迪帕踢门特s】_dept_id ON【昂】 departments【迪帕踢门特s】(dept_id);

3.1 等值连接查询#

  1. 查询每个员工所在的部门名
Use moershi;
select【涩莱克特】 name, dept_name
from【弗乱】 employees【ing普洛伊s】 inner【ing呐】 join【载(白话)】 departments【迪帕踢门特s】 on【昂】 employees【ing普洛伊s】.dept_id=departments【迪帕踢门特s】.dept_id;
-- mysql> select name,dept_name
-- -> from employees inner join departments on employees.dept_id=departments.dept_id;
--
-- | name | dept_name |
-- |-----------|-----------|
-- | 梁伟 | 人事部 |
-- | 郭岩 | 人事部 |
-- | 李玉英 | 人事部 |
-- | 张健 | 人事部 |
-- | 郑静 | 人事部 |
-- | 牛建军 | 人事部 |
-- | 刘斌 | 人事部 |
-- | 汪云 | 人事部 |

2)查询员工编号8 的 员工所在部门的部门名称

select【涩莱克特】 name, dept_name from【弗乱】 employees【ing普洛伊s】 inner【ing呐】 join【载(白话)】 departments【迪帕踢门特s】
on【昂】 employees【ing普洛伊s】.dept_id=departments【迪帕踢门特s】.dept_id where【威尔】 employees【ing普洛伊s】.employee【ing普洛伊】_id=8;
-- mysql> select name,dept_name from employees inner join departments on employees.dept_id=departments.dept_id where employees.employee_id=8;
-- +--------+-----------+
-- | name | dept_name |
-- +--------+-----------+
-- | 汪云 | 人事部 |
-- +--------+-----------+
-- 1 row in set (0.01 sec)

别名规则#

字段名是否必须加别名 e.d.原因说明
dept_id必须因为 employeesdepartments 两个表都有名为 dept_id 的字段,MySQL 无法自动判断您想用的是哪一个。
name不需要因为只有 employees 表中有 name 字段,departments 表中没有这个字段,MySQL 可以唯一确定它来自哪里。

如果字段名在多个表中同时存在,必须带上别名才可以识别你要查询的字段名是那个表的字段名 如果字段名只在其中一个表存在,这就具有唯一性,sql可以明确识别字段名在那个表,就不需要带上别名

3)查询每个员工所有信息及所在的部门名称

给表名定义别名 ,定义别名后必须使用别名表示表名

select【涩莱克特】 e.* , d.dept_name
from【弗乱】 employees【ing普洛伊s】 as e inner【ing呐】 join【载(白话)】 departments【迪帕踢门特s】 as d on【昂】 e.dept_id=d.dept_id;
-- mysql> select e.*,d.dept_name from employees as e inner join departments as d on e.dept_id=d.dept_id limit 5;#结果太多,加上"limit 5" 只输出前5行
-- +-------------+-----------+------------+------------+-----------------------+--------------+---------+-----------+
-- | employee_id | name | hire_date | birth_date | email | phone_number | dept_id | dept_name |
-- +-------------+-----------+------------+------------+-----------------------+--------------+---------+-----------+
-- | 1 | 梁伟 | 2018-06-21 | 1971-08-19 | liangwei@tedu.cn | 13591491431 | 1 | 人事部 |
-- | 2 | 郭岩 | 2010-03-21 | 1974-05-13 | guoyan@tedu.cn | 13845285867 | 1 | 人事部 |
-- | 3 | 李玉英 | 2012-01-19 | 1974-01-25 | liyuying@tedu.cn | 15628557234 | 1 | 人事部 |
-- | 4 | 张健 | 2008-09-17 | 1972-06-07 | zhangjian@moershi.com | 13835990213 | 1 | 人事部 |
-- | 5 | 郑静 | 2018-02-03 | 1997-02-14 | zhengjing@tedu.cn | 14508936730 | 1 | 人事部 |
-- +-------------+-----------+------------+------------+-----------------------+--------------+---------+-----------+
-- 5 rows in set (0.00 sec)

4)查询每个员工姓名、部门编号、部门名称

两个表有同名表头,表头名前必须加表名

select【涩莱克特】 e.dept_id , name , dept_name from【弗乱】 employees【ing普洛伊s】 as e inner【ing呐】 join【载(白话)】 departments【迪帕踢门特s】 as d on【昂】 e.dept_id=d.dept_id;
-- mysql> select e.dept_id,name,dept_name from employees as e inner join departments as d on e.dept_id=d.dept_id limit 5;#结果太多,加上"limit 5" 只输出前5行
-- +---------+-----------+-----------+
-- | dept_id | name | dept_name |
-- +---------+-----------+-----------+
-- | 1 | 梁伟 | 人事部 |
-- | 1 | 郭岩 | 人事部 |
-- | 1 | 李玉英 | 人事部 |
-- | 1 | 张健 | 人事部 |
-- | 1 | 郑静 | 人事部 |
-- +---------+-----------+-----------+
-- 5 rows in set (0.00 sec)

3.2 对连接后的查询结果,筛选、分组、排序、过滤#

1)查询11号员工的名字及2018年每个月总工资

select【涩莱克特】 e.employee【ing普洛伊】_id, name, date, basic【贝斯克】+bonus【波诺斯】 as total【偷ò头ō】
from【弗乱】 employees【ing普洛伊s】 as e inner【ing呐】 join【载(白话)】 salary【撒拉瑞】 as s
on【昂】 e.employee【ing普洛伊】_id=s.employee【ing普洛伊】_id
where【威尔】 year【耶尔】(date)=2018 and e.employee【ing普洛伊】_id=11;
-- mysql>
-- mysql> select e.employee_id,name,date,basic+bonus as total
-- -> from employees as e inner join salary as s on e.employee_id=s.employee_id
-- -> where year(date)=2018 and e.employee_id=11;
-- +-------------+-----------+------------+-------+
-- | employee_id | name | date | total |
-- +-------------+-----------+------------+-------+
-- | 11 | 郭兰英 | 2018-01-10 | 18206 |
-- | 11 | 郭兰英 | 2018-02-10 | 19206 |
-- | 11 | 郭兰英 | 2018-03-10 | 18206 |
-- | 11 | 郭兰英 | 2018-04-10 | 19206 |
-- | 11 | 郭兰英 | 2018-05-10 | 18206 |
-- | 11 | 郭兰英 | 2018-06-10 | 19206 |
-- | 11 | 郭兰英 | 2018-07-10 | 27206 |
-- | 11 | 郭兰英 | 2018-08-10 | 27206 |
-- | 11 | 郭兰英 | 2018-09-10 | 19206 |
-- | 11 | 郭兰英 | 2018-10-10 | 21206 |
-- | 11 | 郭兰英 | 2018-11-10 | 22206 |
-- | 11 | 郭兰英 | 2018-12-10 | 25016 |
-- +-------------+-----------+------------+-------+
-- 12 rows in set (0.00 sec)
-- mysql>

2) 查询每个员工2018年的总工资

#没分组前
select【涩莱克特】 employees【ing普洛伊s】.employee【ing普洛伊】_id,date,basic【贝斯克】,bonus【波诺斯】 from【弗乱】 employees【ing普洛伊s】 inner【ing呐】 join【载(白话)】 salary【撒拉瑞】
on【昂】 employees【ing普洛伊s】.employee【ing普洛伊】_id=salary【撒拉瑞】【撒拉瑞】.employee【ing普洛伊】_id where【威尔】 year【耶尔】(date)=2018;
-- mysql> select employees.employee_id,date,basic,bonus
-- -> from employees inner join salary
-- -> on employees.employee_id=salary.employee_id
-- -> where year(date)=2018;
-- +-------------+------------+-------+-------+
-- | employee_id | date | basic | bonus |
-- +-------------+------------+-------+-------+
-- | 1 | 2018-07-10 | 16206 | 11000 |
-- | 1 | 2018-08-10 | 16206 | 8000 |
-- | 1 | 2018-09-10 | 16206 | 8000 |
-- | 1 | 2018-10-10 | 16206 | 11000 |
-- | 1 | 2018-11-10 | 16206 | 8000 |
-- ...............
-- mysql>
# 分组后
select【涩莱克特】 employees【ing普洛伊s】.employee【ing普洛伊】_id, sum【桑à姆】(basic【贝斯克】+bonus【波诺斯】) from【弗乱】 employees【ing普洛伊s】 inner【ing呐】 join【载(白话)】 salary【撒拉瑞】
on【昂】 employees【ing普洛伊s】.employee【ing普洛伊】_id=salary【撒拉瑞】.employee【ing普洛伊】_id
where【威尔】 year【耶尔】(date)=2018 group【格鲁普】 by employees【ing普洛伊s】.employee【ing普洛伊】_id;
-- mysql>
-- mysql> select employees.employee_id,sum(basic+bonus)
-- -> from employees inner join salary
-- -> on employees.employee_id=salary.employee_id
-- -> where year(date)=2018 --过滤只输出2018年的数据
-- -> group by employees.employee_id; --查询结果以employees.employee_id分组
-- +-------------+------------------+
-- | employee_id | sum(basic+bonus) |
-- +-------------+------------------+
-- | 1 | 151046 |
-- | 2 | 328131 |
-- | 3 | 177595 |
-- | 4 | 262282 |
-- | 5 | 248076 |
-- | 6 | 257282 |
-- | 7 | 314027 |
-- ...............
-- mysql>

3)查询每个员工2018年的总工资,按总工资升序排列

select【涩莱克特】 employees【ing普洛伊s】.employee【ing普洛伊】_id, sum【桑à姆】(basic【贝斯克】+bonus【波诺斯】) as total【偷ò头ō】
from【弗乱】 employees【ing普洛伊s】 inner【ing呐】 join【载(白话)】 salary【撒拉瑞】 on【昂】 employees【ing普洛伊s】.employee【ing普洛伊】_id=salary【撒拉瑞】.employee【ing普洛伊】_id
where【威尔】 year【耶尔】(salary【撒拉瑞】.date)=2018 group【格鲁普】 by employee【ing普洛伊】_id order【欧朵】 by total【偷ò头ō】 asc【阿斯克】;
-- mysql>
-- mysql> select employees.employee_id,sum(basic+bonus) as total
-- -> from employees inner join salary on employees.employee_id=salary.employee_id
-- -> where year(salary.date)=2018 --过滤只输出2018年的数据
-- -> group by employee_id --查询结果以employee_id分组
-- -> order by total asc; --查询结果以升序排序
-- +-------------+--------+
-- | employee_id | total |
-- +-------------+--------+
-- | 8 | 25093 |
-- | 10 | 116389 |
-- | 16 | 119389 |
-- | 51 | 123733 |
-- | 18 | 126687 |
-- .........

4)查询2018年总工资大于30万的员工,按2018年总工资降序排列

select【涩莱克特】 employees【ing普洛伊s】.employee【ing普洛伊】_id, sum【桑à姆】(basic【贝斯克】+bonus【波诺斯】) as total【偷ò头ō】
from【弗乱】 employees【ing普洛伊s】 inner【ing呐】 join【载(白话)】 salary【撒拉瑞】 on【昂】 employees【ing普洛伊s】.employee【ing普洛伊】_id=salary【撒拉瑞】.employee【ing普洛伊】_id
where【威尔】 year【耶尔】(salary【撒拉瑞】.date)=2018
group【格鲁普】 by employees【ing普洛伊s】.employee【ing普洛伊】_id
having【嗨夫营】 total【偷ò头ō】 > 300000
order【欧朵】 by total【偷ò头ō】 desc;
-- mysql>
-- mysql> select employees.employee_id,sum(basic+bonus) as total
-- -> from employees inner join salary on employees.employee_id=salary.employee_id
-- -> where year(salary.date)=2018
-- -> group by employees.employee_id
-- -> having total > 300000
-- -> order by total desc;
-- +-------------+--------+
-- | employee_id | total |
-- +-------------+--------+
-- | 117 | 374923 |
-- | 31 | 374923 |
-- | 37 | 362981 |
-- | 68 | 360923 |
-- | 48 | 359923 |
-- ......

四、外连接查询#

当前任何环节

flowchart LR
subgraph BottomRow[综合查询]
direction LR
A[内连接查询] --> B[外连接查询] --> C[合并查询结果] --> D[嵌套查询]
end
classDef highlight stroke:#f00,stroke-width:2px;
class B highlight;

MySQL 外连接查询是一种在多个表间获取数据的重要方式,它主要分为左外连接、右外连接和全外连接。

外连接类型对比#

连接类型关键字返回结果适用场景
左外连接LEFT【列夫特】 JOIN【载(白话)】LEFT【列夫特】 OUTER【奥特尔】 JOIN【载(白话)】左表所有记录 + 右表匹配记录主表记录必须全部保留,关联表信息可选
右外连接RIGHT【来特】 JOIN【载(白话)】RIGHT【来特】 OUTER【奥特尔】 JOIN【载(白话)】右表所有记录 + 左表匹配记录从表记录必须全部保留,主表信息可选
全外连接FULL【fò】 JOIN【载(白话)】FULL【fò】 OUTER【奥特尔】 JOIN【载(白话)】左右表所有记录需要两个表的完整数据合并

外连接是SQL查询中非常重要的功能,特别适用于:

  • 需要保留主表所有记录的查询
  • 数据完整性检查(查找缺失的关联数据)
  • 生成完整的报表和统计分析
  • 处理可能存在NULL【nò】关联关系的业务场景

左外连接会返回左表中的所有记录,以及右表中匹配的记录,若右表无匹配项,对应字段会显示为 NULL【nò】。右外连接则相反,返回右表所有记录与左表匹配记录。全外连接会返回左右表的所有记录,无匹配项的字段同样显示为 NULL【nò】。

例如员工表和部门表,用左外连接查询时,即便有员工未分配部门,该员工信息也会显示出来。外连接能满足在关联表查询时,不遗漏某表记录的需求。

4.1 左连接查询#

向departments【迪帕踢门特s】表里添加3个部门:小卖部 行政部 公关部

mysql> insert【因涩特】 into【因兔】 departments【迪帕踢门特s】(dept_name) values【挖柳斯】("小卖部"),("行政部"),("公关部");
Query OK, 3 rows affected (0.06 sec)
Records: 3 Duplicates: 0 Warnings: 0

查询部门信息

mysql> select【涩莱克特】 * from【弗乱】 moershi.departments【迪帕踢门特s】;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
| 1 | 人事部 |
| 2 | 财务部 |
| 3 | 运维部 |
| 4 | 开发部 |
| 5 | 测试部 |
| 6 | 市场部 |
| 7 | 销售部 |
| 8 | 法务部 |
| 9 | 小卖部 |
| 10 | 行政部 |
| 11 | 公关部 |
+---------+-----------+
11 rows in set (0.00 sec)
mysql>

左连接查询例子:输出没有员工的部门名

mysql> select【涩莱克特】 d.dept_name,e.name from【弗乱】 departments【迪帕踢门特s】 as d left【列夫特】 join【载(白话)】 employees【ing普洛伊s】 as e on【昂】 d.dept_id=e.dept_id;
...
...
| 法务部 | 王荣 |
| 法务部 | 刘倩 |
| 法务部 | 杨金凤 |
| 小卖部 | NULL |
| 行政部 | NULL |
| 公关部 | NULL |
+-----------+-----------+
136 rows in set (0.00 sec)

连接后 输出与筛选条件匹配的行

select【涩莱克特】 d.dept_name,e.name from【弗乱】 departments【迪帕踢门特s】 as d left【列夫特】 join【载(白话)】 employees【ing普洛伊s】 as e on【昂】 d.dept_id=e.dept_id where【威尔】 e.name is null【nò】;
+-----------+------+
| dept_name | name |
+-----------+------+
| 小卖部 | NULL |
| 行政部 | NULL |
| 公关部 | NULL |
+-----------+------+
3 rows in set (0.01 sec)
mysql>

仅显示departments【迪帕踢门特s】表中dept_name表头

select【涩莱克特】 d.dept_name from【弗乱】 departments【迪帕踢门特s】 as d left【列夫特】 join【载(白话)】 employees【ing普洛伊s】 as e on【昂】 d.dept_id=e.dept_id where【威尔】 e.name is null【nò】;
+-----------+
| dept_name |
+-----------+
| 小卖部 |
| 行政部 |
| 公关部 |
+-----------+
3 rows in set (0.01 sec)
mysql>

4.2 右连接查询#

向employees【ing普洛伊s】表中添加3个员工 只给name表头赋值

insert【因涩特】 into【因兔】 employees【ing普洛伊s】(name) values【挖柳斯】("bob"),("tom"),("lily");
Query OK, 3 rows affected (0.05 sec)
Records: 3 Duplicates: 0 Warnings: 0

右连接查询例子:显示没有部门的员工名

//右连接查询
select【涩莱克特】 e.name ,d.dept_name from【弗乱】 departments【迪帕踢门特s】 as d right【来特】 join【载(白话)】 employees【ing普洛伊s】 as e on【昂】 d.dept_id=e.dept_id;
//加筛选条件
select【涩莱克特】 e.name ,d.dept_name from【弗乱】 departments【迪帕踢门特s】 as d right【来特】 join【载(白话)】 employees【ing普洛伊s】 as e on【昂】 d.dept_id=e.dept_id where【威尔】 d.dept_name is null【nò】 ;
+------+-----------+
| name | dept_name |
+------+-----------+
| bob | NULL |
| tom | NULL |
| lily | NULL |
+------+-----------+
3 rows in set (0.00 sec)
mysql>
//仅显示员工名
select【涩莱克特】 e.name from【弗乱】 departments【迪帕踢门特s】 as d right【来特】 join【载(白话)】 employees【ing普洛伊s】 as e on【昂】 d.dept_id=e.dept_id where【威尔】 d.dept_name is null【nò】 ;
+------+
| name |
+------+
| bob |
| tom |
| lily |
+------+

五、合并查询结果#

当前任务环节

flowchart LR
subgraph BottomRow[综合查询]
direction LR
A[内连接查询] --> B[外连接查询] --> C[合并查询结果] --> D[嵌套查询]
end
classDef highlight stroke:#f00,stroke-width:2px;
class C highlight;

在 MySQL 综合查询里,合并查询是一种实用的操作。它主要用于将多个查询结果合并成一个结果集,使用的关键字是 UNION【U凝】UNION【U凝】 ALL【ò】

UNION【U凝】 会去除合并结果里的重复记录,只保留一条。比如,你分别从员工表查询出薪资大于 8000 的员工,和从另一筛选条件查出的员工,用 UNION【U凝】 合并后,相同员工就只显示一次。而 UNION【U凝】 ALL【ò】 不会去重,会把所有查询结果直接合并。当你需要查看所有相关数据,不在意重复时,就用 UNION【U凝】 ALL【ò】。合并查询让你能灵活整合不同查询的数据。

基本概念对比#

特性UNION【U凝】UNION【U凝】 ALL【ò】
去重处理自动去除重复行保留所有行,包括重复行
性能较慢(需要排序和去重)较快(直接合并)
结果排序默认按第一列升序排列不保证顺序
语法SELECT【涩莱克特】 ... UNION【U凝】 SELECT【涩莱克特】 ...SELECT【涩莱克特】 ... UNION【U凝】 ALL【ò】 SELECT【涩莱克特】 ...
使用场景需要唯一结果时需要完整数据或已知无重复时
--------------------------------------------
去重能力✅ 自动去重❌ 保留重复
执行性能⭐⭐ 较慢⭐⭐⭐⭐ 较快
内存消耗较高较低
结果顺序默认排序不保证顺序
使用频率⭐⭐⭐ 常用⭐⭐⭐⭐⭐ 更常用
适用场景需要唯一结果完整数据或性能优先

关键要点总结

  1. UNION【U凝】 ALL【ò】 通常比 UNION【U凝】 性能更好,因为它不需要去重操作
  2. 只有需要去除重复记录时才使用 UNION【U凝】
  3. 确保所有SELECT【涩莱克特】语句的列数、数据类型和顺序一致
  4. UNION【U凝】 ALL【ò】 保留所有记录,包括重复项
  5. 在合并大量数据时,UNION【U凝】 ALL【ò】 是更优选择

基本语法格式#

UNION【U凝】 语法

SELECT【涩莱克特】 列名1, 列名2, ...
FROM【弗乱】 表1
WHERE【威尔】 条件
UNION【U凝】
SELECT【涩莱克特】 列名1, 列名2, ...
FROM【弗乱】 表2
WHERE【威尔】 条件;

UNION 【U凝】ALL【ò】 语法

SELECT【涩莱克特】 列名1, 列名2, ...
FROM【弗乱】 表1
WHERE【威尔】 条件
UNION【U凝】 ALL【ò】
SELECT【涩莱克特】 列名1, 列名2, ...
FROM【弗乱】 表2
WHERE【威尔】 条件;

性能对比分析#

操作步骤UNION【U凝】UNION【U凝】 ALL【ò】
数据读取读取所有数据读取所有数据
排序处理对结果进行排序不需要排序
去重操作比较并去除重复行保留所有行
内存使用较高较低
执行时间较长较短

实际示例演示#

输出2018年基本工资的最大值和最小值

mysql> ( select【涩莱克特】 basic【贝斯克】 from【弗乱】 salary【撒拉瑞】 where【威尔】 year【耶尔】(date)=2018 order【欧朵】 by basic【贝斯克】 desc limit 1) union【U凝】 (select【涩莱克特】 basic【贝斯克】 from【弗乱】 salary【撒拉瑞】 where【威尔】 year【耶尔】(date)=2018 order【欧朵】 by basic【贝斯克】 asc【阿斯克】 limit【肋梅特】 1 );
-- mysql> (select basic from salary where year(date)=2018 order by basic desc limit 1)
-- -> union
-- -> (select basic from salary where year(date)=2018 order by basic asc limit 1);
-- +----------------+
-- | basic【贝斯克】 |
-- +----------------+
-- | 25524 |
-- | 5787 |
-- +----------------+
-- 2 rows in set (0.01 sec)

输出2018年1月10号 基本工资的最大值和最小值

mysql> (select【涩莱克特】 date , max【mà 斯】(basic【贝斯克】) as 工资 from【弗乱】 salary【撒拉瑞】 where【威尔】 date=20180110) union【U凝】(select【涩莱克特】 date,min【敏ì】(basic【贝斯克】) from【弗乱】 salary【撒拉瑞】 where【威尔】 date=20180110);
-- mysql> (select date,max(basic) as 工资 from salary where date=20180110)
-- -> union
-- -> (select date,min(basic) from salary where date=20180110);
-- +------------+--------+
-- | date | 工资 |
-- +------------+--------+
-- | 2018-01-10 | 24309 |
-- | 2018-01-10 | 5787 |
-- +------------+--------+
-- 2 rows in set (0.01 sec)

union【U凝】 去掉查询结果中重复的行

mysql> (select【涩莱克特】 employee【ing普洛伊】_id , name , birth【波尔斯】_date from【弗乱】 employees【ing普洛伊s】 where【威尔】 employee【ing普洛伊】_id <= 5) union【U凝】 (select【涩莱克特】 employee【ing普洛伊】_id , name , birth【波尔斯】_date from【弗乱】 employees【ing普洛伊s】 where【威尔】 employee【ing普洛伊】_id <= 6);
-- mysql> (select employee_id,name,birth_date from employees where employee_id <=5)
-- -> union
-- -> (select employee_id,name,birth_date from employees where employee_id <=6);
+-------------------------+-----------+------------+
| employee【ing普洛伊】_id | name | birth_date |
+-------------------------+-----------+------------+
| 1 | 梁伟 | 1971-08-19 |
| 2 | 郭岩 | 1974-05-13 |
| 3 | 李玉英 | 1974-01-25 |
| 4 | 张健 | 1972-06-07 |
| 5 | 郑静 | 1997-02-14 |
| 6 | 牛建军 | 1985-03-19 |
+------------------------+-----------+------------+

第二个查询只输出了与条件匹配的最后1行

mysql> (select【涩莱克特】 employee【ing普洛伊】_id , name , birth【波尔斯】_date from【弗乱】 employees【ing普洛伊s】 where【威尔】 employee【ing普洛伊】_id <= 5) union【U凝】 (select【涩莱克特】 employee【ing普洛伊】_id , name , birth【波尔斯】_date from【弗乱】 employees【ing普洛伊s】 where【威尔】 employee【ing普洛伊】_id <= 6);
-- mysql> (select employee_id,name,birth_date from employees where employee_id <=5)
-- -> union
-- -> (select employee_id,name,birth_date from employees where employee_id <=6);
+------------------------+-----------+-------------+
| employee【ing普洛伊】_id | name | birth【波尔斯】_date |
+------------------------+-----------+-------------+
| 1 | 梁伟 | 1971-08-19 |
| 2 | 郭岩 | 1974-05-13 |
| 3 | 李玉英 | 1974-01-25 |
| 4 | 张健 | 1972-06-07 |
| 5 | 郑静 | 1997-02-14 |
| 6 | 牛建军 | 1985-03-19 |
+------------------------+-----------+-------------+
6 rows in set (0.00 sec)

union【U凝】 all 不去重显示查询结果

mysql> (select【涩莱克特】 employee【ing普洛伊】_id , name , birth【波尔斯】_date from【弗乱】 employees【ing普洛伊s】 where【威尔】 employee【ing普洛伊】_id <= 5) union【U凝】 all【ò】 (select【涩莱克特】 employee【ing普洛伊】_id , name , birth【波尔斯】_date from【弗乱】 employees【ing普洛伊s】 where【威尔】 employee【ing普洛伊】_id <= 6);
-- mysql> (select employee_id,name,birth_date from employees where employee_id <=5)
-- -> union all
-- -> (select employee_id,name,birth_date from employees where employee_id <=6);
+-------------+-----------+------------+
| employee_id | name | birth_date |
+-------------+-----------+------------+
| 1 | 梁伟 | 1971-08-19 |
| 2 | 郭岩 | 1974-05-13 |
| 3 | 李玉英 | 1974-01-25 |
| 4 | 张健 | 1972-06-07 |
| 5 | 郑静 | 1997-02-14 |
| 1 | 梁伟 | 1971-08-19 |
| 2 | 郭岩 | 1974-05-13 |
| 3 | 李玉英 | 1974-01-25 |
| 4 | 张健 | 1972-06-07 |
| 5 | 郑静 | 1997-02-14 |
| 6 | 牛建军 | 1985-03-19 |
+-------------+-----------+------------+
11 rows in set (0.00 sec)

六、嵌套查询#

当前任务环节

flowchart LR
subgraph BottomRow[综合查询]
direction LR
A[内连接查询] --> B[外连接查询] --> C[合并查询结果] --> D[嵌套查询]
end
classDef highlight stroke:#f00,stroke-width:2px;
class D highlight;

嵌套查询:是指在一个完整的查询语句之中,包含若干个不同功能的小查询;从而一起完成复杂查询的一种编写形式。包含的查询放在()里 , 包含的查询出现的位置:

  • SELECT【涩莱克特】之后
  • FROM【弗乱】之后
  • WHERE【威尔】
  • HAVING【嗨夫营】之后

嵌套查询的作用#

1. 数据筛选与过滤#

  • 在主查询中使用子查询的结果作为筛选条件
  • 实现复杂的多条件数据过滤

2. 数据比较与计算#

  • 将子查询结果与主查询数据进行对比
  • 计算相对值、百分比等复杂指标

3. 数据存在性检查#

  • 检查某条记录是否存在于另一个表中
  • 验证数据的完整性

4. 数据聚合与统计#

  • 在子查询中进行分组统计
  • 将统计结果用于主查询的条件判断

嵌套查询的优势#

  1. 逻辑清晰:将复杂问题分解为多个简单步骤
  2. 灵活性高:可以处理各种复杂的数据关系
  3. 可读性强:SQL语句结构清晰,易于理解
  4. 功能强大:支持多层嵌套,解决复杂业务逻辑

注意事项#

  1. 性能考虑:多层嵌套可能影响查询性能
  2. 可维护性:过度嵌套会使SQL难以维护
  3. 替代方案:考虑使用JOIN或CTE(公共表表达式)作为替代方案

6.1 where【威尔】之后嵌套查询#

1)查询运维部所有员工信息

#先把 运维部的id 找到
mysql> select【涩莱克特】 dept_id from【弗乱】 departments【迪帕踢门特s】 where【威尔】 dept_name="运维部";
-- mysql> select dept_id from departments where dept_name="运维部";
+---------+
| dept_id |
+---------+
| 3 |
+---------+
1 row in set (0.00 sec)
#员工表里没有部门名称 但有部门编号 (和部门表的编号是一致的)
mysql> select【涩莱克特】 * from【弗乱】 employees【ing普洛伊s】 where【威尔】 dept_id = (select【涩莱克特】 dept_id from【弗乱】 departments【迪帕踢门特s】 where【威尔】 dept_name="运维部");
-- mysql> select * from employees where dept_id=(select dept_id from departments where dept_name="运维部");
+-------------+-----------+------------+---------------------+--------------------+--------------+---------+
| employee_id | name | hire_date | birth【波尔斯】_date | email | phone_number | dept_id |
+-------------+-----------+------------+---------------------+--------------------+--------------+---------+
| 14 | 廖娜 | 2012-05-20 | 1982-06-22 | liaona@moershi.com | 15827928192 | 3 |
| 15 | 窦红梅 | 2018-03-16 | 1971-09-09 | douhongmei@qcjy.cn | 15004739483 | 3 |
| 16 | 聂想 | 2018-09-09 | 1999-06-05 | niexiang@qcjy.cn | 15501892446 | 3 |
| 17 | 陈阳 | 2004-09-16 | 1991-04-10 | chenyang@qcjy.cn | 15565662056 | 3 |
| 18 | 戴璐 | 2001-11-30 | 1975-05-16 | dailu@qcjy.cn | 13465236095 | 3 |
| 19 | 陈斌 | 2019-07-04 | 2000-01-22 | chenbin@moershi.com | 13621656037 | 3 |
+-------------+-----------+------------+---------------------+--------------------+--------------+---------+
6 rows in set (0.00 sec)

2)查询人事部2018年12月所有员工工资

//查看人事部的部门id
mysql> select【涩莱克特】 dept_id from【弗乱】 departments【迪帕踢门特s】 where【威尔】 dept_name='人事部';
-- mysql> select dept_id from departments where dept_name='人事部';
+---------+
| dept_id |
+---------+
| 1 |
+---------+
1 row in set (0.00 sec)
//查找employees【ing普洛伊s】表里 人事部的员工id
select【涩莱克特】 employee【ing普洛伊】_id from【弗乱】 employees【ing普洛伊s】 where【威尔】 dept_id=(select【涩莱克特】 dept_id from【弗乱】 departments【迪帕踢门特s】 where【威尔】 dept_name='人事部');
-- mysql> select employee_id from employees where dept_id=(select dept_id from departments where dept_name='人事部');
+-------------+
| employee_id |
+-------------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
+-------------+
8 rows in set (0.00 sec)
//查询人事部2018年12月所有员工工资
select【涩莱克特】 * from【弗乱】 salary【撒拉瑞】 where【威尔】 year【耶尔】(date)=2018 and month【mèn斯】(date)=12
and employee【ing普洛伊】_id in (select【涩莱克特】 employee【ing普洛伊】_id from【弗乱】 employees【ing普洛伊s】
where【威尔】 dept_id=(select【涩莱克特】 dept_id from【弗乱】 departments【迪帕踢门特s】 where【威尔】 dept_name='人事部') );
-- mysql> select * from salary where year(date)=2018 and month(date)=12
-- -> and employee_id in (select employee_id from employees
-- -> where dept_id=(select dept_id from departments where dept_name='人事部'));
+------+------------+-------------+----------------+----------------+
| id | date | employee_id | basic【贝斯克】 | bonus【波诺斯】 |
+------+------------+-------------+----------------+----------------+
| 6252 | 2018-12-10 | 1 | 17016 | 7000 |
| 6253 | 2018-12-10 | 2 | 20662 | 9000 |
| 6254 | 2018-12-10 | 3 | 9724 | 8000 |
| 6255 | 2018-12-10 | 4 | 17016 | 2000 |
| 6256 | 2018-12-10 | 5 | 17016 | 3000 |
| 6257 | 2018-12-10 | 6 | 17016 | 1000 |
| 6258 | 2018-12-10 | 7 | 23093 | 4000 |
| 6259 | 2018-12-10 | 8 | 23093 | 2000 |
+------+------------+-------------+----------------+----------------+
8 rows in set (0.00 sec)

3)查询人事部和财务部员工信息

//查看人事部和财务部的 部门id
select【涩莱克特】 dept_id from【弗乱】 departments【迪帕踢门特s】 where【威尔】 dept_name in ('人事部', '财务部');
-- mysql> select dept_id from departments where dept_name in ('人事部','财务部');
+---------+
| dept_id |
+---------+
| 1 |
| 2 |
+---------+
2 rows in set (0.00 sec)
//查询人事部和财务部员工信息
select【涩莱克特】 dept_id , name from【弗乱】 employees【ing普洛伊s】
where【威尔】 dept_id in (
select【涩莱克特】 dept_id from【弗乱】 departments【迪帕踢门特s】 where【威尔】 dept_name in ('人事部', '财务部')
);
-- mysql> select dept_id,name from employees
-- -> where dept_id in (
-- -> select dept_id from departments where dept_name in ('人事部','财务部'));
+---------+-----------+
| dept_id | name |
+---------+-----------+
| 1 | 梁伟 |
| 1 | 郭岩 |
| 1 | 李玉英 |
| 1 | 张健 |
| 1 | 郑静 |
| 1 | 牛建军 |
| 1 | 刘斌 |
| 1 | 汪云 |
| 2 | 张建平 |
| 2 | 郭娟 |
| 2 | 郭兰英 |
| 2 | 王英 |
| 2 | 王楠 |
+---------+-----------+
13 rows in set (0.00 sec)

4)查询2018年12月所有比100号员工基本工资高的工资信息

//把100号员工的基本工资查出来
select【涩莱克特】 basic【贝斯克】 from【弗乱】 salary【撒拉瑞】 where【威尔】 year【耶尔】(date)=2018 and
month【mèn斯】(date)=12 and employee【ing普洛伊】_id=100;
-- mysql> select basic from salary where year(date)=2018 and
-- -> month(date)=12 and employee_id=100;
+----------------+
| basic【贝斯克】 |
+----------------+
| 14585 |
+----------------+
1 row in set (0.00 sec)
//查看比100号员工工资高的工资信息
select【涩莱克特】 * from【弗乱】 salary【撒拉瑞】
where【威尔】 year【耶尔】(date)=2018 and month【mèn斯】(date)=12 and
basic【贝斯克】>(select【涩莱克特】 basic【贝斯克】 from【弗乱】 salary【撒拉瑞】 where【威尔】 year【耶尔】(date)=2018 and
month【mèn斯】(date)=12 and employee【ing普洛伊】_id=100);
-- mysql> select * from salary
-- -> where year(date)=2018 and month(date)=12 and
-- -> basic > (select basic from salary where year(date)=2018 and
-- -> month(date)=12 and employee_id=100);
+------+------------+-------------+----------------+----------------+
| id | date | employee_id | basic【贝斯克】 | bonus【波诺斯】 |
+------+------------+-------------+----------------+----------------+
| 6252 | 2018-12-10 | 1 | 17016 | 7000 |
| 6253 | 2018-12-10 | 2 | 20662 | 9000 |
| 6255 | 2018-12-10 | 4 | 17016 | 2000 |
| 6256 | 2018-12-10 | 5 | 17016 | 3000 |
| 6257 | 2018-12-10 | 6 | 17016 | 1000 |
| 6258 | 2018-12-10 | 7 | 23093 | 4000 |
| 6259 | 2018-12-10 | 8 | 23093 | 2000 |
| 6261 | 2018-12-10 | 10 | 21878 | 8000 |
| 6262 | 2018-12-10 | 11 | 17016 | 8000 |
| 6263 | 2018-12-10 | 12 | 15800 | 4000 |
| 6264 | 2018-12-10 | 13 | 18231 | 3000 |
| 6267 | 2018-12-10 | 16 | 21878 | 8000 |
| 6268 | 2018-12-10 | 17 | 19448 | 7000 |
| 6271 | 2018-12-10 | 20 | 19448 | 3000 |
| 6272 | 2018-12-10 | 21 | 18231 | 11000 |
| 6276 | 2018-12-10 | 25 | 23093 | 3000 |
| 6278 | 2018-12-10 | 27 | 24309 | 5000 |
| 6279 | 2018-12-10 | 28 | 17016 | 9000 |
| 6280 | 2018-12-10 | 29 | 23093 | 1000 |
| 6282 | 2018-12-10 | 31 | 25524 | 9000 |
| 6283 | 2018-12-10 | 32 | 18231 | 11000 |
| 6284 | 2018-12-10 | 33 | 23093 | 6000 |
| 6285 | 2018-12-10 | 34 | 23093 | 1000 |
| 6288 | 2018-12-10 | 37 | 24309 | 4000 |
| 6289 | 2018-12-10 | 38 | 23093 | 3000 |
| 6291 | 2018-12-10 | 40 | 20662 | 2000 |
| 6297 | 2018-12-10 | 46 | 15800 | 7000 |
| 6299 | 2018-12-10 | 48 | 25524 | 1000 |
| 6300 | 2018-12-10 | 49 | 15800 | 9000 |
| 6303 | 2018-12-10 | 52 | 19448 | 9000 |
| 6304 | 2018-12-10 | 53 | 25524 | 8000 |
| 6305 | 2018-12-10 | 54 | 21878 | 9000 |
| 6307 | 2018-12-10 | 56 | 23093 | 3000 |
| 6308 | 2018-12-10 | 57 | 23093 | 3000 |
| 6312 | 2018-12-10 | 61 | 24309 | 3000 |
| 6313 | 2018-12-10 | 62 | 15800 | 4000 |
| 6314 | 2018-12-10 | 63 | 15800 | 8000 |
| 6317 | 2018-12-10 | 66 | 19448 | 7000 |
| 6319 | 2018-12-10 | 68 | 25524 | 9000 |
| 6324 | 2018-12-10 | 73 | 17016 | 10000 |
| 6327 | 2018-12-10 | 76 | 20662 | 11000 |
| 6330 | 2018-12-10 | 79 | 15800 | 4000 |
| 6332 | 2018-12-10 | 81 | 17016 | 3000 |
| 6336 | 2018-12-10 | 85 | 15800 | 1000 |
| 6337 | 2018-12-10 | 86 | 24309 | 4000 |
| 6339 | 2018-12-10 | 88 | 20662 | 2000 |
| 6342 | 2018-12-10 | 91 | 20662 | 11000 |
| 6343 | 2018-12-10 | 92 | 19448 | 2000 |
| 6346 | 2018-12-10 | 95 | 19448 | 8000 |
| 6349 | 2018-12-10 | 98 | 19448 | 9000 |
| 6350 | 2018-12-10 | 99 | 15800 | 5000 |
| 6353 | 2018-12-10 | 102 | 23093 | 3000 |
| 6356 | 2018-12-10 | 105 | 21878 | 8000 |
| 6357 | 2018-12-10 | 106 | 23093 | 5000 |
| 6358 | 2018-12-10 | 107 | 18231 | 7000 |
| 6359 | 2018-12-10 | 108 | 18231 | 2000 |
| 6361 | 2018-12-10 | 110 | 18231 | 2000 |
| 6363 | 2018-12-10 | 112 | 24309 | 9000 |
| 6368 | 2018-12-10 | 117 | 25524 | 11000 |
| 6369 | 2018-12-10 | 118 | 23093 | 3000 |
| 6370 | 2018-12-10 | 119 | 23093 | 10000 |
| 6373 | 2018-12-10 | 122 | 21878 | 2000 |
| 6374 | 2018-12-10 | 123 | 19448 | 10000 |
| 6376 | 2018-12-10 | 125 | 17016 | 5000 |
| 6378 | 2018-12-10 | 127 | 17016 | 6000 |
+------+------------+-------------+----------------+----------------+
65 rows in set (0.01 sec)

6.2 having【嗨夫营】之后嵌套查询#

查询部门员工总人数比开发部总人数少 的 部门名称和人数

//统计开发部员工总人数
select【涩莱克特】 count【kàn特】(name) from【弗乱】 employees【ing普洛伊s】 where【威尔】 dept_id = (select【涩莱克特】
dept_id from【弗乱】 departments【迪帕踢门特s】 where【威尔】 dept_name="开发部");
-- mysql> select count(name) from employees where dept_id=
-- -> (select dept_id from departments where dept_name="开发部");
+---------------------+
| count【kàn特】(name) |
+---------------------+
| 55 |
+---------------------+
1 row in set (0.00 sec)
//统计每个部门总人数
select【涩莱克特】 dept_id , count【kàn特】(name) from【弗乱】 employees【ing普洛伊s】 group【格鲁普】 by dept_id;
-- mysql> select dept_id,count(name) from employees group by dept_id;
+---------+---------------------+
| dept_id | count【kàn特】(name) |
+---------+---------------------+
| 1 | 8 |
| 2 | 5 |
| 3 | 6 |
| 4 | 55 |
| 5 | 12 |
| 6 | 9 |
| 7 | 35 |
| 8 | 3 |
+---------+---------------------+
8 rows in set (0.00 sec)
//输出总人数比开发部总人数少的部门名及总人数
select【涩莱克特】 dept_id , count【kàn特】(name) as total【偷ò头ō】 from【弗乱】 employees【ing普洛伊s】 group【格鲁普】 by dept_id
having【嗨夫营】 total【偷ò头ō】 < (
select【涩莱克特】 count【kàn特】(name) from【弗乱】 employees【ing普洛伊s】 where【威尔】 dept_id=(
select【涩莱克特】 dept_id from【弗乱】 departments【迪帕踢门特s】 where【威尔】 dept_name='开发部')
);
-- mysql> select dept_id,count(name) as total from employees group by dept_id
-- -> having total < (select count(name) from employees where dept_id= (select
-- -> dept_id from departments where dept_name='开发部'));
+---------+----------------+
| dept_id | total【偷ò头ō】 |
+---------+----------------+
| 1 | 8 |
| 2 | 5 |
| 3 | 6 |
| 5 | 12 |
| 6 | 9 |
| 7 | 35 |
| 8 | 3 |
+---------+----------------+
7 rows in set (0.00 sec)

6.3 from【弗乱】之后嵌套查询#

查询3号部门 、部门名称 及其部门内 员工的编号、名字 和 email

select【涩莱克特】 dept_id, dept_name, employee【ing普洛伊】_id, name, email from【弗乱】 (
select【涩莱克特】 d.dept_name, e.* from【弗乱】 departments【迪帕踢门特s】 as d inner【ing呐】 join【载(白话)】 employees【ing普洛伊s】 as e
on【昂】 d.dept_id=e.dept_id ) as tmp_table【忒-部】 where【威尔】 dept_id=3;
-- mysql> select dept_id,dept_name,employee_id,name,email from
-- -> (select d.dept_name,e.* from departments as d inner join employees as e
-- -> on d.dept_id=e.dept_id) as tmp_toble where dept_id=3;
+---------+-----------+-------------+-----------+--------------------+
| dept_id | dept_name | employee_id | name | email |
+---------+-----------+-------------+-----------+--------------------+
| 3 | 运维部 | 14 | 廖娜 | liaona@moershi.com |
| 3 | 运维部 | 15 | 窦红梅 | douhongmei@qcjy.cn |
| 3 | 运维部 | 16 | 聂想 | niexiang@qcjy.cn |
| 3 | 运维部 | 17 | 陈阳 | chenyang@qcjy.cn |
| 3 | 运维部 | 18 | 戴璐 | dailu@qcjy.cn |
| 3 | 运维部 | 19 | 陈斌 | chenbin@moershi.com |
+---------+-----------+-------------+-----------+--------------------+
6 rows in set (0.00 sec)

6.4 select【涩莱克特】之后嵌套查询#

查询每个部门的人数: dept_id dept_name 部门人数

//显示部门表中的所有列表
select【涩莱克特】 d.* from【弗乱】 departments【迪帕踢门特s】 as d;
-- mysql> select d.* from departments as d;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
| 1 | 人事部 |
| 2 | 财务部 |
| 3 | 运维部 |
| 4 | 开发部 |
| 5 | 测试部 |
| 6 | 市场部 |
| 7 | 销售部 |
| 8 | 法务部 |
+---------+-----------+
8 rows in set (0.00 sec)
//查询每个部门的人数
select【涩莱克特】 d.* , ( select【涩莱克特】 count【kàn特】(name) from【弗乱】 employees【ing普洛伊s】 as e where【威尔】 d.dept_id=e.dept_id) as 部门人数 from【弗乱】 departments【迪帕踢门特s】 as d;
-- mysql> select d.*,(select count(name) from employees as e where d.dept_id=e.dept_id) as 部门人数
-- -> from departments as d;
+---------+-----------+--------------+
| dept_id | dept_name | 部门人数 |
+---------+-----------+--------------+
| 1 | 人事部 | 8 |
| 2 | 财务部 | 5 |
| 3 | 运维部 | 6 |
| 4 | 开发部 | 55 |
| 5 | 测试部 | 12 |
| 6 | 市场部 | 9 |
| 7 | 销售部 | 35 |
| 8 | 法务部 | 3 |
+---------+-----------+--------------+
8 rows in set (0.00 sec)

七、作业#

1 选择题#

  1. 在内连接查询中,使用以下哪种关键字进行连接操作?C A. LEFT JOIN B. RIGHT JOIN C. INNER JOIN D. FULL JOIN
  2. 外连接查询中,左外连接会返回以下哪些数据?A A. 左表的所有记录和右表匹配的记录 B. 右表的所有记录和左表匹配的记录 C. 左右表的所有记录 D. 只返回左右表匹配的记录
  3. 合并查询中,UNION ALLUNION 的区别是? B A. UNION ALL 会去除重复记录,UNION 不会 B. UNION 会去除重复记录,UNION ALL 不会 C. 两者都去除重复记录 D. 两者都不去除重复记录
  4. 嵌套查询是指?B A. 在一个查询语句中嵌套多个表 B. 在一个查询语句中嵌套另一个查询语句 C. 同时进行多个查询操作 D. 以上都不对

2 简答题#

  1. 简述内连接查询和外连接查询的区别。 答: 内连接是:只保留匹配的记录(交集) 外链接是:保留至少一个表的所有记录,不匹配的用NULL填充 应用场景区别:内连接用于需要精确匹配的场景,外连接用于需要保留所有记录的统计分析

  2. 什么时候使用 UNION,什么时候使用 UNION ALL? 答: 需要唯一结果的时候可以使用UNION 当需要完整数据或性能优先 时候使用 UNION ALL

  3. 请解释嵌套查询的作用和适用场景。 答: 嵌套查询的作用 1. 数据筛选与过滤 2. 数据比较与计算 3. 数据存在性检查 4. 数据聚合与统计

    特别适合需要多步骤数据处理和分析的业务场景。

3 操作题#

  1. 使用内连接查询,查询出每个员工所在部门的名称和员工姓名。
mysql>
mysql> select e.name,d.dept_name from employees as e inner join departments as d
-> on e.dept_id=d.dept_id;
+-----------+-----------+
| name | dept_name |
+-----------+-----------+
| 梁伟 | 人事部 |
| 郭岩 | 人事部 |
| 李玉英 | 人事部 |
| 张健 | 人事部 |
.........
  1. 使用左外连接查询,查询出所有员工的信息以及他们所在部门的名称(如果员工没有部门,部门名称显示为 NULL)。
mysql>
mysql> select e.*,d.dept_name from employees as e left join departments as d on e.dept_id=d.dept_id;
+-------------+-----------+------------+------------+---------------------------+--------------+---------+-----------+
| employee_id | name | hire_date | birth_date | email | phone_number | dept_id | dept_name |
+-------------+-----------+------------+------------+---------------------------+--------------+---------+-----------+
| 1 | 梁伟 | 2018-06-21 | 1971-08-19 | liangwei@tedu.cn | 13591491431 | 1 | 人事部 |
| 2 | 郭岩 | 2010-03-21 | 1974-05-13 | guoyan@tedu.cn | 13845285867 | 1 | 人事部 |
| 3 | 李玉英 | 2012-01-19 | 1974-01-25 | liyuying@tedu.cn | 15628557234 | 1 | 人事部 |
| 4 | 张健 | 2008-09-17 | 1972-06-07 | zhangjian@moershi.com | 13835990213 | 1 | 人事部 |
| 5 | 郑静 | 2018-02-03 | 1997-02-14 | zhengjing@tedu.cn | 14508936730 | 1 | 人事部 |
| 6 | 牛建军 | 2005-11-18 | 1985-03-19 | niujianjun@moershi.com | 14750937118 | 1 | 人事部 |
......
  1. 使用合并查询,将薪资表中基本薪资大于 5000 和奖金大于 2000 的记录合并。
mysql> (select name,basic from salary as s inner join employees as e on e.employee_id=s.employee_id where basic > 5000)
-> union
-> (select name,bonus from salary as s inner join employees as e on e.employee_id=s.employee_id where bonus >2000);
+-----------+-------+
| name | basic |
+-----------+-------+
| 郭岩 | 17000 |
| 李玉英 | 8000 |
| 张健 | 14000 |
| 牛建军 | 14000 |
| 刘斌 | 19000 |
| 郭兰英 | 14000 |
| 王楠 | 15000 |
| 廖娜 | 10000 |
| 陈阳 | 16000 |
.....
  1. 使用嵌套查询,查询出部门名称为 “开发部” 的所有员工的信息。
mysql>
mysql> select * from employees where dept_id=
-> (select dept_id from departments where dept_name='开发部');
+-------------+-----------+------------+------------+---------------------------+--------------+---------+
| employee_id | name | hire_date | birth_date | email | phone_number | dept_id |
+-------------+-----------+------------+------------+---------------------------+--------------+---------+
| 20 | 蒋红 | 2017-12-29 | 1978-01-24 | jianghong@tedu.cn | 15852915398 | 4 |
| 21 | 曹宁 | 2004-06-07 | 1988-01-05 | caoning@tedu.cn | 14513022304 | 4 |
| 22 | 吕刚 | 2014-01-18 | 1980-06-24 | lvgang@tedu.cn | 18136987619 | 4 |
| 23 | 王莉 | 2021-02-04 | 1972-12-19 | wangli@moershi.com | 15376329290 | 4 |
| 24 | 邓秀芳 | 2020-09-08 | 1980-12-12 | dengxiufang@moershi.com | 15884927117 | 4 |
| 25 | 邵佳 | 2011-08-15 | 1978-11-28 | shaojia@tedu.cn | 13296016750 | 4 |
| 26 | 党丽 | 2014-03-14 | 1978-12-30 | dangli@moershi.com | 13166234580 | 4 |
| 27 | 梁勇 | 2007-01-19 | 1997-11-12 | liangyong@tedu.cn | 15307868657 | 4 |
| 28 | 郑秀珍 | 2011-04-28 | 1972-09-01 | zhengxiuzhen@moershi.com | 14543186401 | 4 |
| 29 | 胡秀云 | 2003-11-03 | 2000-05-14 | huxiuyun@tedu.cn | 18212266720 | 4 |
| 30 | 邢淑兰 | 2011-07-02 | 1989-06-17 | xingshulan@moershi.com | 13032270370 | 4 |
| 31 | 刘海燕 | 2018-01-06 | 1982-08-21 | liuhaiyan@moershi.com | 15064354651 | 4 |
| 32 | 冯建国 | 2014-05-28 | 1980-01-26 | fengjianguo@tedu.cn | 13344957322 | 4 |
.........
04:mysql之综合查询
https://fuwari.vercel.app/posts/数据库/04-mysql之综合查询/
作者
肥猫少杰
发布于
2026-06-03
许可协议
CC BY-NC-SA 4.0