【MySQL】复合查询

> 作者:დ旧言~

> 座右铭:松树千年终是朽,槿花一日自为荣。

> 目标:了解复合查询的关键字,并能熟练使用。

> 毒鸡汤:有些事情,总是不明白,所以我不会坚持。早安!

> 专栏选自:带你玩转MySQL

> 望小伙伴们点赞👍收藏✨加关注哟💕💕

​​

一、前言

想必大家在学校也学习过MySQL,可能学的懵懵懂懂,这个板块我们从入门开始,从最新的安装MySQL到学习MySQL语句,一步一步开始,一切都是新的,新的板块新的开始,大家一起努力,一起进步!!!

主体

学习【MySQL】复合查询咱们按照下面的图解:

2.1基本查询回顾

给出三张表,员工表(emp)、部门表(dept)和工资等级表(salgrade):

emp员工表:

cpp 复制代码
mysql> select * from emp;
+--------+--------+-----------+------+---------------------+---------+---------+--------+
| empno  | ename  | job       | mgr  | hiredate            | sal     | comm    | deptno |
+--------+--------+-----------+------+---------------------+---------+---------+--------+
| 007369 | SMITH  | CLERK     | 7902 | 1980-12-17 00:00:00 |  800.00 |    NULL |     20 |
| 007499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 00:00:00 | 1600.00 |  300.00 |     30 |
| 007521 | WARD   | SALESMAN  | 7698 | 1981-02-22 00:00:00 | 1250.00 |  500.00 |     30 |
| 007566 | JONES  | MANAGER   | 7839 | 1981-04-02 00:00:00 | 2975.00 |    NULL |     20 |
| 007654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 |     30 |
| 007698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 00:00:00 | 2850.00 |    NULL |     30 |
| 007782 | CLARK  | MANAGER   | 7839 | 1981-06-09 00:00:00 | 2450.00 |    NULL |     10 |
| 007788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 00:00:00 | 3000.00 |    NULL |     20 |
| 007839 | KING   | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 |    NULL |     10 |
| 007844 | TURNER | SALESMAN  | 7698 | 1981-09-08 00:00:00 | 1500.00 |    0.00 |     30 |
| 007876 | ADAMS  | CLERK     | 7788 | 1987-05-23 00:00:00 | 1100.00 |    NULL |     20 |
| 007900 | JAMES  | CLERK     | 7698 | 1981-12-03 00:00:00 |  950.00 |    NULL |     30 |
| 007902 | FORD   | ANALYST   | 7566 | 1981-12-03 00:00:00 | 3000.00 |    NULL |     20 |
| 007934 | MILLER | CLERK     | 7782 | 1982-01-23 00:00:00 | 1300.00 |    NULL |     10 |
+--------+--------+-----------+------+---------------------+---------+---------+--------+
14 rows in set (0.00 sec)

dept部门表:

cpp 复制代码
mysql> select * from dept;
+--------+------------+----------+
| deptno | dname      | loc      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+
4 rows in set (0.00 sec)

salgrade工资等级表:

cpp 复制代码
mysql> select * from salgrade;
+-------+-------+-------+
| grade | losal | hisal |
+-------+-------+-------+
|     1 |   700 |  1200 |
|     2 |  1201 |  1400 |
|     3 |  1401 |  2000 |
|     4 |  2001 |  3000 |
|     5 |  3001 |  9999 |
+-------+-------+-------+
5 rows in set (0.00 sec)

基本查询使用:

1.查询工资高于500或岗位为MANAGER的员工,同时要求员工姓名的首字母为大写的J:

cpp 复制代码
select ename,sal,job from emp where (sal>500 or ename='MANAGER') and ename like 'J%';

2.查询员工信息,按照部门号升序而雇员的工资降序排序:

cpp 复制代码
select ename,deptno,sal from emp order by deptno asc,sal desc;

3.查询员工信息,按年薪降序显示:

cpp 复制代码
select ename,sal*12+ifnull(comm,0) 年薪 from emp order by 年薪 desc;
  • 由于NULL与任何值做计算得到的结果都是NULL,因此在计算年薪时不能直接用月薪的12倍加上每个员工的奖金,这样可能导致得到的年薪为NULL值。
  • 在计算每个员工的年薪时,应该通过ifnull函数判断员工的奖金是否为NULL,如果不为NULL则ifnull函数返回员工的奖金,如果为NULL则ifnull函数返回0,避免让NULL值参与计算。

4.查询工资最高的员工的姓名和岗位:

cpp 复制代码
select ename,job from emp where sal=(select max(sal) from emp);

5.查询工资高于平均工资的员工信息:

cpp 复制代码
select ename,sal from emp where sal > (select avg(sal) from emp);

6.查询每个部门的平均工资和最高工资:

cpp 复制代码
select deptno,avg(sal) 平均工资,max(sal) 最高工资 from emp group by deptno;

7.查询平均工资低于2000的部门和它的平均工资:

cpp 复制代码
select deptno,avg(sal) 平均工资 from emp group by deptno having 平均工资<2000;

8.查询每种岗位的雇员总数和平均工资:

cpp 复制代码
select job,count(*) 雇员总数,avg(sal) 平均工资 from emp group by job;

2.2多表查询


2.2.1多表查询概念

概念:

上面的基础查询都是在一张表的基础上进行的查询,而实际开发中往往需要将多张表关联起来进行查询,这就叫做多表查询。

  • 在进行多表查询时,只需要将多张表的表名依次放到from子句之后,用逗号隔开即可,这时MySQL将会对给定的这多张表取笛卡尔积,作为多表查询的初始数据源。
  • 多表查询的本质,就是对给定的多张表取笛卡尔积,然后在笛卡尔积中进行查询。

图解:

简单使用多表查询:

2.2.2案例分析

1.显示部门号为10的部门名,员工名和工资:

cpp 复制代码
select dname,ename,sal from emp,dept where emp.deptno=dept.deptno and emp.deptno=10;

2.显示各个员工的姓名,工资,及工资级别:

cpp 复制代码
select ename,sal,grade from emp,salgrade where sal between losal and hisal;

2.3自连接

概念:

自连接是指在同一张表连接查询。

举个栗子:

显示员工FORD的上级领导的编号和姓名:

方法一:使用子查询

cpp 复制代码
select empno,ename from emp where empno=(select mgr from emp where ename='FORD');

方法二:使用多表查询(自查询)

cpp 复制代码
mysql> select leader.empno,leader.ename from emp worker,emp leader 
    -> where worker.ename='FORD' and worker.mgr=leader.empno;

注意:

  • 由于自连接是对同一张表取笛卡尔积,因此在自连接时至少需要给一张表取别名,否则无法区分这两张表中的列。

2.4子查询

概念:

  • 子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询。

2.4.1单行子查询

概念:

  • 单行子查询,是指返回单行单列数据的子查询。

举个栗子:

显示SMITH同一部门的员工:

cpp 复制代码
select * from emp where deptno=(select deptno from emp where ename='SMITH') and ename<>'SMITH';

2.4.2多行子查询

**概念:**返回多行记录的子查询。

  • IN:表示存在,即需满足存在条件
  • ALL:表示所有,即需满足所有条件
  • ANY:表示任一,即需满足任一条件

举个栗子:

1.IN关键字:查询和10号部门的工作岗位相同的雇员的名字,岗位,工资,部门号,但是不包含10号部门自己的:

  1. 首先查询出10号部门所有的岗位
  2. 然后将这些岗位信息作为下一次查询的筛选条件进行查询
  3. 最后去掉10号部门的员工信息
cpp 复制代码
mysql> select ename,job,sal,deptno from emp 
    -> where job in (select distinct job from emp where deptno=10) and deptno<>10;

2.ALL关键字:显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号:

  1. 首先查找出30号部门所有的员工工资
  2. 然后将其作为筛选条件查找出比30号部门的所有员工工资都高的员工信息
cpp 复制代码
mysql> select ename,sal,deptno from emp 
    -> where sal > all(select distinct sal from emp where deptno=30);

3.ANY关键字:显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门的员工):

cpp 复制代码
mysql> select ename,sal,deptno from emp
    -> where sal > any (select distinct sal from emp where deptno=30);

2.4.3多列子查询

概念:

单行子查询是指子查询只返回单列,单行数据;多行子查询是指返回单列多行数据,都是针对单列而言的。而多列子查询则是指查询返回多个列数据的子查询语句。

举个栗子:

1.显示和SMITH的部门和岗位完全相同的员工,不包含SMITH本人:

  1. 首先查找出SMITH的部门号和岗位信息
  2. 然后以SMITH的部门号和岗位信息作为筛选条件进行筛选
  3. 最后去掉SMITH的相关信息
cpp 复制代码
mysql> select * from emp 
    -> where (deptno,job)=(select deptno,job from emp where ename='SMITH') and ename<>'SMITH';

2.4.4 在from子句中使用子查询

概念:

子查询语句出现在from子句中。这里要用到数据查询的技巧,把一个子查询当做一个临时表使用。

举个栗子:

1.显示每个高于自己部门平均工资的员工的姓名、部门、工资和部门的平均工资:

  1. 首先对部门进行分组,获取其部门号即平均工资
  2. 将查询结果作为一张临时表,获取其与emp表的笛卡尔积
  3. 最后在笛卡尔积表当中筛选出每个高于自己部门平均工资的员工的姓名、部门、工资、平均工资
cpp 复制代码
mysql> select ename,emp.deptno,sal,平均工资
    -> from emp,(select deptno,avg(sal) 平均工资 from emp group by deptno) tmp
    -> where emp.deptno=tmp.deptno and sal > 平均工资;

2.显示每个部门工资最高的员工的姓名、工资、部门和部门的最高工资:

  1. 首先分组查询获取每个部门的部门号和最高工资
  2. 然后将查询结果作为临时表,并获取其与emp表的笛卡尔积
  3. 从获取的笛卡尔积中筛选出每个部门工资最高的人的姓名、工资、部门、最高工资
cpp 复制代码
mysql> select ename,sal,emp.deptno,最高工资
    -> from emp,(select deptno,max(sal) 最高工资 from emp group by deptno) tmp
    -> where emp.deptno=tmp.deptno and sal=最高工资;

3.显示每个部门的信息(部门名,编号,地址)和人员数量:

  1. 首先对部门进行分组,查找每个部门对应的人数
  2. 将查询的结果作为临时表,获取其与dept表的笛卡尔积
  3. 从笛卡尔积表中筛选出每个部门的信息及其部门人数
cpp 复制代码
mysql> select dname,dept.deptno,loc,人员数量
    -> from dept,(select deptno,count(*) 人员数量 from emp group by deptno) tmp
    -> where dept.deptno=tmp.deptno;

2.4.5合并查询

概念:

合并查询 是指多个查询结果进行合并,可使用的操作符有 union 和 union all。

  • union 用于取得两个查询结果的并集,union会自动去掉结果集中的重复行。
  • union all也用于取得两个查询结果的并集,但union all 不会去掉结果集中的重复行。
2.4.5.1 UNION

概念:

该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行。

举个栗子:

将工资大于2500或职位是MANAGER的人找出来:

cpp 复制代码
mysql> select ename,sal,job from emp where sal>2500
    -> union
    -> select ename,sal,job from emp where job='MANAGER';
2.4.5.2 UNION ALL

概念:

该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行。

举个栗子:

将工资大于2500或职位是MANAGER的人找出来:

总结:

此时可以发现UNION和UNION ALL的唯一区别就是前者会对查找结果进行去重,而后者不会。

三、结束语

今天内容就到这里啦,时间过得很快,大家沉下心来好好学习,会有一定的收获的,大家多多坚持,嘻嘻,成功路上注定孤独,因为坚持的人不多。那请大家举起自己的小手给博主一键三连,有你们的支持是我最大的动力💞💞💞,回见。

​​ 、

相关推荐
苹果醋31 小时前
React源码02 - 基础知识 React API 一览
java·运维·spring boot·mysql·nginx
C4rpeDime1 小时前
自建MD5解密平台-续
android
别致的影分身2 小时前
使用C语言连接MySQL
数据库·mysql
过过过呀Glik2 小时前
在 Ubuntu 上安装 MySQL 的详细指南
mysql·ubuntu
鲤籽鲲3 小时前
C# Random 随机数 全面解析
android·java·c#
Sunyanhui15 小时前
牛客网 SQL36查找后排序
数据库·sql·mysql
老王笔记5 小时前
MHA binlog server
数据库·mysql
m0_548514776 小时前
2024.12.10——攻防世界Web_php_include
android·前端·php
凤邪摩羯7 小时前
Android-性能优化-03-启动优化-启动耗时
android
凤邪摩羯7 小时前
Android-性能优化-02-内存优化-LeakCanary原理解析
android