首页 > 数据库 >MySQL的子查询(二十)

MySQL的子查询(二十)

时间:2022-11-10 15:03:30浏览次数:48  
标签:deptId 二十 age 查询 user MySQL where select


勿以恶小而为之,勿以善小而不为--------------------------刘备

上一章简单介绍了 MySQL的多表连接查询(十九),如果没有看过,​​请观看上一章​​

一 . MySQL的子查询

一.一 子查询的产生

子查询指的是,在一个完整的查询语句里面,嵌套几个不同功能的小查询语句,从而一起完成一个复杂的查询 。 简单来说,就是 功能小查询语句的输出,是完整查询语句的输入, 类似于 Linux 系统中的 管道符 |

如找出与 岳泽霖是同一个部门的员工。

那么需要分两步:

第一步: 从 user 表里面找出 姓名 name 为岳泽霖的员工,查询出其员工编号。

select t.deptId from user t where t.name='岳泽霖';

查询出结果 部门编号为1。

MySQL的子查询(二十)_MySQL的子查询

第二步: 从 user 表里面找出 部门编号为 1的员工,并且去除掉 ‘岳泽霖’

select * from user t where t.deptId=1 and t.name <> '岳泽霖' ;

MySQL的子查询(二十)_操作符_02

这是两条语句,需要依次进行查询。 那么,能不能变成一条语句进行查询呢?
需要将第一步的结果放置到第二步里面。
这就是子查询。 是sql查询语句的批处理。

一.二 子查询的输出结果分类

子查询,即功能小查询语句的输出结果,按照查询出的数据结果划分的话,可以分成四类:

  1. 单行单列       (标量子查询)
  2. 单行多列        (列子查询)
  3. 多行单列        (行子查询)
  4. 多行多列        (表子查询)

单行单列 返回一个具体列的内容,是一个确定的值, 可以是字符串,也可以是普通数字,还可以是日期。

单行多列 就是从表中查询出 符合条件的某一行的多个列值。

多行单列 就是从表中 查询出符合条件的某一列的多个行值。

多行多列 就是从表中查询出符合条件的 多个行,多个列的值,是一个新的二维数据表,常用作临时表。

一.三 子查询出现的位置

子查询一般出现在 where 和having 语句后面, 也可以出现在 select 和 from 语句的后面,
但一般以 where 和having 居多。

其中,

在where 语句后面出现的子查询 可以为 单行单列,单行多列,多行单列

在 having 语句后面出现的子查询 为单行单列,用于统计函数,如count() avg() 等。

在 from 语句后面出现的子查询为 多行多列, 作为临时表。

老蝴蝶 根据子查询出现的不同的位置,做不同的讲解。

仍然使用的是 yuejl 数据库里面的 dept 表和 user 表。

MySQL的子查询(二十)_操作符_03

二 . where 语句 的子查询

在where 语句后面,常常出现 单行单列,单行多列,多行单列的子查询。

下面,老蝴蝶 分别进行讲解。

二.一 单行单列 (=,<>,> 等 操作符)

单行单列,返回的是一个固定的值, 常常用 = , != , >, < 这样的操作符, 具体使用哪一个,要根据要求选择。

问题1 : 查询出 与 岳泽霖 同一个部门的员工。

需要分三步:

  1. 查询出 员工 岳泽霖 的所在部门
select t.deptId from user t where t.name='岳泽霖';

MySQL的子查询(二十)_操作符_04

  1. 根据第一步的部门编号 查询出所有的员工
select * from user a where a.deptId=(select t.deptId from user t where t.name='岳泽霖');

MySQL的子查询(二十)_子查询_05

  1. 从第三步的员工里面 去除掉 姓名为 岳泽霖的员工
select * from user a where a.deptId=(select t.deptId from user t where t.name='岳泽霖')
and a.name <> '岳泽霖';

MySQL的子查询(二十)_MySQL的子查询_06

与岳泽霖 同一个部门的员工 有 两个蝴蝶飞和精灵妹。

问题2:查询出比 两个蝴蝶飞 年龄大的员工

需要分两步:

  1. 查询出 两个蝴蝶飞的年龄
select t.age from user t where t.name='两个蝴蝶飞';

MySQL的子查询(二十)_子查询_07

  1. 从user表里面查询出所有 年龄大于 第一步两个蝴蝶飞年龄的员工
select * from user a where a.age > (
select t.age from user t where t.name='两个蝴蝶飞'
);

MySQL的子查询(二十)_多列_08

问题3 : 查询出与岳泽霖 同一个部门,并且年龄小于岳泽霖的 员工。

主要是为了说明, where 后面可以跟多个子查询语句

需要分四步:

  1. 查询出岳泽霖所在的部门编号
  2. 查询出岳泽霖的年龄
  3. 从user表里面根据部门编号去查询所有的员工
  4. 从第三步结果里面进行筛选,筛选条件为 年龄 小于第二步的年龄

直接写sql语句 为

select * from user t where t.deptId=(select deptId from user where name='岳泽霖')
and t.age < (select age from user where name='岳泽霖');

MySQL的子查询(二十)_多列_09

这两个人都 符合条件 。

二.二 单行多列 (=,<> 操作符)

查询出多个列值, 那么需要将多个列值封装成一个元组,即(列值1,列值2…), 利用元组进行判断, 而元组判断只能是 = (相同), <> (不相同) 其中 元组的 = 表示 元组里面的所有的列值都相同。 <> 表示元组里面的所有的列值有一个不同即可。

= 与 <> 是互补的。

问题1: 查询出与 两个蝴蝶飞 性别相同,年龄相同的 员工。

需要分三步:

  1. 查询出两个蝴蝶飞的性别和年龄
select * from user t where t.name='两个蝴蝶飞';

MySQL的子查询(二十)_子查询_10

2 . 从user 表里面查询出 性别和年龄 为 第一步结果的值

select * from user a where (a.sex,a.age)=(
select t.sex,t.age from user t where t.name='两个蝴蝶飞'
);

MySQL的子查询(二十)_操作符_11

3 . 从第三步里面筛选出 名称不为两个蝴蝶飞的员工

select * from user a where (a.sex,a.age)=(
select t.sex,t.age from user t where t.name='两个蝴蝶飞'
) and a.name <> '两个蝴蝶飞';

MySQL的子查询(二十)_操作符_12

与两个蝴蝶飞 性别相同,年龄也相同的 只有 老蝴蝶 一个人。

问题 2 : 查询出与 两个蝴蝶飞 性别不相同,或者年龄 也不相同的员工。

是第一个问题的补集。 用 <> 代替问题1中的 =号即可。

select * from user a where (a.sex,a.age) <> (
select t.sex,t.age from user t where t.name='两个蝴蝶飞'
) and a.name <> '两个蝴蝶飞';

MySQL的子查询(二十)_MySQL的子查询_13

问题 3: 查询出 与两个蝴蝶飞 性别,年龄,和出生日期 均相同的员工。

主要是说明,可以放置多个列, 但一般都是两个列。

直接写 查询语句为 :

select * from user a where (a.sex,a.age,a.birthday)=(
select t.sex,t.age,t.birthday from user t where t.name='两个蝴蝶飞'
) and a.name <> '两个蝴蝶飞';

MySQL的子查询(二十)_多列_14

二.三 多行单列 (in ,any,all 操作符)

为了更准确的展示数据,先把 user 表进行一下改变, 添加一些新员工数据,修改一下老员工的年龄。

修改完成之后的数据为:

select * from user;

MySQL的子查询(二十)_多列_15

查询出多个行同一列的值,数据类型是相同的,即 查询出一个数组。 那么有关数组的操作, 如 最大的值,最小的值,是否存在于数组 等就可以在数据库中进行体现了。 常见的有 in,any, all 三个操作符

二.三.一 in 操作符

in 表示在里面, not in 表示不在里面。

问题1: 查询出每一个部门,与最大年龄相同的员工。

需要三个步骤:

1 . 查询出每一个部门的最大年龄。 用分组和聚合函数 max

select max(age) from user group by deptId;

MySQL的子查询(二十)_操作符_16

  1. 查询出员工的年龄 在第一步骤里面的员工
select * from user where age in (select max(age) from user group by deptId);

MySQL的子查询(二十)_操作符_17

查询出年龄 在 25,23,21 中的所有的员工。 与以前的操作符 in 是相同的。

问题2 : 查询出每一个部门,不与最大年龄相同的员工。

即 not in 操作符, 与以前的 not in 操作符是相同的。

select * from user where age not in (select max(age) from user group by deptId);

MySQL的子查询(二十)_MySQL的子查询_18

二.三.二 any(some) 操作符

any 表示 任何一个。 有三种符号

= any , 表示与其中任意一个相同即可。

> any, 比其中任意一个大即可, 即 大于 范围内的最小值即可

< any , 比其中任意一个小即可,即 小于范围内的最大值即可。

> ,< 均不 包括 = ,如果想表示等于, 可以用 >= any, <=any

还有一个 <> any, 这个并不等于 not in .

any 与 some 是相同的意思, 但一般都 用 any 来统一表示。

其中, 每一个部门的最大员工的年龄为:

select max(age) from user group by deptId;

MySQL的子查询(二十)_操作符_16


为 25,23,21 。

1 .为 =any 时, 与任意一个相同。 此时 与in 是一致的。

select * from user where age =any (select max(age) from user group by deptId);

MySQL的子查询(二十)_操作符_20

2 . 为 > any 时,大于范围内的最小值, 即 年龄大于21即可。

select * from user where age > any (select max(age) from user group by deptId);

MySQL的子查询(二十)_操作符_21

会将部门 1中的年龄为24的 员工 ‘精灵妹’ 查询出来。

3 . 为 >= any 时,大于等于范围内的最小值, 即年龄 大于等于21即可。

select * from user where age >= any (select max(age) from user group by deptId);

MySQL的子查询(二十)_多列_22


包含了21, 会将年龄为 21的员工也查询出来。

4 . 为< any时, 小于范围内的最大值, 即 年龄小于 25 即可。

select * from user where age < any (select max(age) from user group by deptId);

MySQL的子查询(二十)_MySQL的子查询_23

会查询出那些为 18和 20 的员工

5 . 为<= any 时,小于等于范围内的最大值, 即年龄大于等于 25即可。

select * from user where age <= any (select max(age) from user group by deptId);

MySQL的子查询(二十)_多列_24


会将年龄为25的员工也查询出来。

6 为 <> any时, 看看是什么情况

select * from user where age <> any (select max(age) from user group by deptId);

MySQL的子查询(二十)_操作符_25

发现 会将所有的内容 都 查询出来 了。

<> any 并不常用。 想表达 not in 的用法时,常常使用的是 <> all .

二.三.三 all 操作符

all 是全部, 有以下三种常见的情况。

<> all , 不等于其中的任意一个, 即 not in 的意思

> all, 大于所有的, 即 比其中最大的值还要大。

< all, 小于所有的, 即比其中最小的值还要小。

1 . <> all 时, 不等于其中的任意一个

select * from user where age <> all (select max(age) from user group by deptId);

MySQL的子查询(二十)_操作符_26

与 not in 的结果是一样的。

2. > all, 大于所有的,比其中最大的25 还要大

select * from user where age > all (select max(age) from user group by deptId);

MySQL的子查询(二十)_多列_27

没有比25还大的。

3 >= all, 大于等于所有的, 比其中最大的25还要大,或者是相同。

select * from user where age >= all (select max(age) from user group by deptId);

MySQL的子查询(二十)_子查询_28

会把 25的查询出来

4 < all, 小于所有的, 比其中最小的21 还要小

select * from user where age < all (select max(age) from user group by deptId);

MySQL的子查询(二十)_操作符_29

5 <= all, 小于等于所有的,比其中最小的21还要小,或者是相同的。

select * from user where age <= all (select max(age) from user group by deptId);

MySQL的子查询(二十)_子查询_30

二.四 exists 和 not exists

exists 会查询的结果进行判断,如果exists 后面跟的子查询 至少返回 一行, 那么就返回 true,会执行最外侧的查询语句,
如果没有返回一行,那么就返回false,不执行最外侧的那个查询语句

exists 后面的子查询 要用() 进行扩起来。

not exists 与 exists 正好相反

问题1 . 查询一下是否存在编号为1的部门编号,如果存在,则将该部门下的员工查询出来,如果不存在,则不查询任何记录。

这样 判断形式的,可以用 exists 来进行处理

select * from user where exists (select * from dept where id=1) and deptId=1;

MySQL的子查询(二十)_操作符_31

看一下,是否存在部门编号为207 的。 (部门表里面没有编号为207的数据)

select * from user where exists (select * from dept where id=207) and deptId=207;

MySQL的子查询(二十)_操作符_32

没有查询出任何记录

问题 2. not exists 是对 exists 进行的取反操作

select * from user where not exists (select * from dept where id=1) and deptId=1;

MySQL的子查询(二十)_多列_33

三. having 语句的子查询

having 后面的子查询,主要用于分组后的筛选, 与分组统计有关的。
后面只有一种用法,跟的是 单行单列的值。

问题1 : 查询每个部门的平均年龄大于公司的平均年龄的所有部门及其该部门的平均年龄。

需要分三步:

第一步: 查询出公司的平均年龄 ,即 user表的平均年龄

select avg(age) from user;

MySQL的子查询(二十)_多列_34

第二步: 查询每个部门的平均年龄

select deptId,avg(age) from user group by deptId;

MySQL的子查询(二十)_MySQL的子查询_35

可以简单看出,只有 部门编号为1的才符合。

第三步: 在group by 分组后, 利用 having 进行筛选

select deptId,avg(age) as dage from user group by deptId
having dage >(select avg(age) from user) ;

MySQL的子查询(二十)_子查询_36

四.from 语句的子查询

from 后面的子查询,是多行多列的,是一个临时表, 表示从临时表里面查询数据。 (一般会将这样的临时表,处理成视图)

问题 1: 查询 每个部门的编号,名称 和 员工的最大年龄。

主要分成两步:

  1. 连接部门表和员工表,查询出 部门的编号,部门的名称 和员工的姓名,员工的年龄。
select a.id as deptId,a.name as deptName,b.name as userName,b.age as userAge from dept a left join user b 
on a.id=b.deptId;

MySQL的子查询(二十)_操作符_37

2 . 从第一步的结果里面 进行分组, 按照部门编号,部门名称进行分组,查询出最大的年龄

select c.deptId,c.deptName,max(c.userAge) from (
select a.id as deptId,a.name as deptName,b.name as userName,b.age as userAge from dept a left join user b
on a.id=b.deptId
) c
group by c.deptId,c.deptName;

MySQL的子查询(二十)_MySQL的子查询_38

其中, from 后面的子查询 一般比较复杂,需要小心对待。

五. select 语句的子查询

select 语句的子查询,一般不常使用。

如 查询出每个部门的编号,部门名称,和该部门的平均年龄

需要将 平均年龄处理成列的形式。

select d.id,d.name,
(select avg(u.age) from user u where u.deptId=d.id) as davg_age
from dept d;

MySQL的子查询(二十)_MySQL的子查询_39

这样查询,效率很低,所以一般不在select 时进行子查询。

子查询一定要记住 where 和having 的常见用法。





谢谢!!!


标签:deptId,二十,age,查询,user,MySQL,where,select
From: https://blog.51cto.com/u_13420484/5841641

相关文章

  • MySQL合并查询结果(二十一)
    勿以恶小而为之,勿以善小而不为--------------------------刘备上一章简单介绍了MySQL的子查询(二十),如果没有看过,​​请观看上一章​​一.合并查询结果多条sql查询语句......
  • MySQL的索引(二十三)
    勿以恶小而为之,勿以善小而不为--------------------------刘备上一章简单介绍了MySQL的视图(二十二),如果没有看过,​​请观看上一章​​一.索引一.一索引的产生前面已经......
  • MySQL的视图(二十二)
    勿以恶小而为之,勿以善小而不为--------------------------刘备上一章简单介绍了MySQL合并查询结果(二十一),如果没有看过,​​请观看上一章​​一.视图一.一视图的出现......
  • Mongodb数据库和MySQL的比较
    谈谈Mongodb和MySQL的区别什么是Mongodb数据库Mongodb是一个介于关系数据库和非关系数据库之间的产品(Nosql),非关系型数据库(nosql),属于文档型数据库。文档是mongoDB......
  • 一个 MySQL 隐式转换的坑,差点把服务器整崩溃了
    我是风筝,公众号「古时的风筝」,专注于Java技术及周边生态。文章会收录在​​JavaNewBee​​中,更有Java后端知识图谱,从小白到大牛要走的路都在里面。本来是一个平静而......
  • 为什么说MySQL单表行数不要超过2000w?
    作为在后端圈开车的多年老司机,是不是经常听到过,“mysql单表最好不要超过2000w”,“单表超过2000w就要考虑数据迁移了”,“你这个表数据都马上要到2000w了,难怪查询速度......
  • 解决golang报错:imports github.com/go-sql-driver/mysql from implicitly required mo
    这句话的意思是,从隐式的引入模块导入的比如我使用某个第三方包,这个第三方包里面包含了mysql包我在代码里直接使用了这个mysql包,但是在go.mod里没有引入,代码里ide是不会报......
  • 安装mysql 5.7教程
    前言:因为个人工作原因安装mysql5.7版本,中间还遇到各种错误所以自己总结一下1.安装当然第一步还是安装可以自己到官网下载也可以在清华源上下载下载安装包官网下载(不......
  • MySQL为什么有时候会选错索引?以及什么情况索引会失效?
    MySQL为什么有时候会选错索引?MySQL判断选择哪个索引时,这个是优化器的工作。优化器会根据扫描的行数、是否回表、是否使用临时表、排序等来判断使用索引还是全表扫......
  • 分别在mysql和postgreSQL中存储json对象
    1.添加maven依赖<dependency><groupId>com.vladmihalcea</groupId><artifactId>hibernate-types-52</artifactId><version>${hibernate-types.version}</v......