MySQL_第09章_子查询

news2024/12/23 9:28:38

09_子查询

讲师:尚硅谷 - 宋红康(江湖人称:康师傅)
官网: http://www.atguigu.com
子查询指一个查询语句嵌套在另一个查询语句内部的查询,这个特性从 MySQL 4.1 开始引入。
SQL 中子查询的使用大大增强了 SELECT 查询的能力,因为很多时候查询需要从结果集中获取数据,或者需要从同一个表中先计算得出一个数据结果,然后与这个数据结果(可能是某个标量,也可能是某个集合)进行比较。

1. 需求分析与问题解决

1.1 实际问题

 现有解决方式:

# 方式一:
SELECT salary
FROM employees
WHERE last_name = 'Abel' ;
SELECT last_name,salary
FROM employees
WHERE salary > 11000 ;
# 方式二:自连接
SELECT e2 .last_name ,e2 .salary
FROM employees e1,employees e2
WHERE e1 .last_name = 'Abel'
AND e1. `salary` < e2. `salary`
# 方式三:子查询
SELECT last_name,salary
FROM employees
WHERE salary > (
SELECT salary
FROM employees
WHERE last_name = 'Abel'
);

 

1.2 子查询的基本使用

  • 子查询的基本语法结构:

  • 子查询(内查询)在主查询之前一次执行完成。
  • 子查询的结果被主查询(外查询)使用 。
  • 注意事项
    • 子查询要包含在括号内
    • 将子查询放在比较条件的右侧
    • 单行操作符对应单行子查询,多行操作符对应多行子查询

1.3 子查询的分类

分类方式 1
我们按内查询的结果返回一条还是多条记录,将子查询分为 单行子查询 多行子查询
  • 单行子查询

 

  • 多行子查询

 

分类方式 2
我们按内查询是否被执行多次,将子查询划分为 相关 ( 或关联 ) 子查询 不相关 ( 或非关联 ) 子查询
子查询从数据表中查询了数据结果,如果这个数据结果只执行一次,然后这个数据结果作为主查询的条件进行执行,那么这样的子查询叫做不相关子查询。
同样,如果子查询需要执行多次,即采用循环的方式,先从外部查询开始,每次都传入子查询进行查询,然后再将结果反馈给外部,这种嵌套的执行方式就称为相关子查询。

2. 单行子查询

2.1 单行比较操作符

操作符
含义
=
equal to
>
greater than
>=
greater than or equal to
<
less than
<=
less than or equal to
<>
not equal to

2.2 代码示例

题目:查询工资大于 149 号员工工资的员工的信息

 

题目:返回job_id141号员工相同,salary143号员工多的员工姓名,job_id和工资 

SELECT last_name, job_id, salary
FROM employees
WHERE job_id =
( SELECT job_id
FROM employees
WHERE employee_id = 141 )
AND salary >
( SELECT salary
FROM employees
WHERE employee_id = 143 );

 

 

题目:返回公司工资最少的员工的 last_name,job_id salary
SELECT last_name, job_id, salary
FROM employees
WHERE salary =
( SELECT MIN(salary)
FROM employees);

  

题目:查询与 141 号或 174 号员工的 manager_id department_id 相同的其他员工的 employee_id manager_id department_id
实现方式 1 :不成对比较
SELECT employee_id, manager_id, department_id
FROM employees
WHERE manager_id IN
(SELECT manager_id
FROM employees
WHERE employee_id IN (174,141))
AND department_id IN
(SELECT department_id
FROM employees
WHERE employee_id IN (174,141))
AND employee_id NOT IN(174,141);
实现方式 2 :成对比较
SELECT employee_id, manager_id, department_id
FROM employees
WHERE (manager_id, department_id) IN
(SELECT manager_id, department_id
FROM employees
WHERE employee_id IN (141,174))
AND employee_id NOT IN (141,174);

2.3 HAVING 中的子查询

  • 首先执行子查询。
  • 向主查询中的HAVING 子句返回结果。
题目:查询最低工资大于 50 号部门最低工资的部门 id 和其最低工资
SELECT department_id, MIN(salary)
FROM employees
GROUP BY department_id
HAVING MIN(salary) >
( SELECT MIN(salary)
FROM employees
WHERE department_id = 50 );

2.4 CASE中的子查询

CASE 表达式中使用单列子查询:
题目:显式员工的 employee_id,last_name location 。其中,若员工 department_id location_id 1800 department_id 相同,则 location ’Canada’ ,其余则为 ’USA’
SELECT employee_id, last_name,
(CASE department_id
WHEN
(SELECT department_id FROM departments
WHERE location_id = 1800)
THEN 'Canada' ELSE 'USA' END) location
FROM employees;

2.5 子查询中的空值问题

SELECT last_name, job_id
FROM employees
WHERE job_id =
( SELECT job_id
FROM employees
WHERE last_name = 'Haas' );

 子查询不返回任何行

2.5 非法使用子查询

SELECT employee_id, last_name
FROM employees
WHERE salary =
( SELECT MIN(salary)
FROM employees
GROUP BY department_id);

 

多行子查询使用单行比较符

3. 多行子查询

  • 也称为集合比较子查询
  • 内查询返回多行
  • 使用多行比较操作符

3.1 多行比较操作符

操作符
含义
IN
等于列表中的 任意一个
ANY
需要和单行比较操作符一起使用,和子查询返回的 某一个 值比较
ALL
需要和单行比较操作符一起使用,和子查询返回的 所有 值比较
SOME
实际上是 ANY 的别名,作用相同,一般常使用 ANY
体会 ANY ALL 的区别

3.2 代码示例

题目:返回其它 job_id 中比 job_id ‘IT_PROG’ 部门任一工资低的员工的员工号、姓名、 job_id 以及 salary

 

 

 

题目:返回其它 job_id 中比 job_id ‘IT_PROG’ 部门所有工资都低的员工的员工号、姓名、 job_id 以及 salary

 

 

题目:查询平均工资最低的部门 id
# 方式 1
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG (salary) = (
SELECT MIN (avg_sal)
FROM (
SELECT AVG (salary) avg_sal
FROM employees
GROUP BY department_id
) dept_avg_sal
)
# 方式 2
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG (salary) <= ALL (
SELECT AVG (salary) avg_sal
FROM employees
GROUP BY department_id
)

3.3 空值问题

SELECT last_name
FROM employees
WHERE employee_id NOT IN (
SELECT manager_id
FROM employees
);

 

4. 相关子查询

4.1 相关子查询执行流程

如果子查询的执行依赖于外部查询,通常情况下都是因为子查询中的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重新计算一次,这样的子查询就称之为 关联子查询
相关子查询按照一行接一行的顺序执行,主查询的每一行都执行一次子查询。

 

 

说明: 子查询中使用主查询中的列

4.2 代码示例

题目:查询员工中工资大于本部门平均工资的员工的 last_name,salary 和其 department_id
方式一:相关子查询

 

方式二:在 FROM 中使用子查询
SELECT last_name,salary,e1 .department_id
FROM employees e1,( SELECT department_id,AVG(salary) dept_avg_sal FROM employees GROUP
BY department_id) e2
WHERE e1.`department_id` = e2 .department_id
AND e2 .dept_avg_sal < e1.`salary`;
from 型的子查询:子查询是作为 from 的一部分,子查询要用 () 引起来,并且要给这个子查询取别名, 把它当成一张“ 临时的虚拟的表 来使用。
ORDER BY 中使用子查询:
题目:查询员工的 id,salary, 按照 department_name 排序
SELECT employee_id,salary
FROM employees e
ORDER BY (
SELECT department_name
FROM departments d
WHERE e.`department_id` = d.`department_id`
);
题目:若 employees 表中 employee_id job_history 表中 employee_id 相同的数目不小于 2 ,输出这些相同 id 的员工的 employee_id,last_name 和其 job_id
SELECT e.employee_id, last_name,e.job_id
FROM employees e
WHERE 2 <= (SELECT COUNT(*)
FROM job_history
WHERE employee_id = e.employee_id);

4.3 EXISTS NOT EXISTS关键字

  • 关联子查询通常也会和 EXISTS操作符一起来使用,用来检查在子查询中是否存在满足条件的行。
  • 如果在子查询中不存在满足条件的行:
    • 条件返回 FALSE
    • 继续在子查询中查找
  • 如果在子查询中存在满足条件的行:
    • 不在子查询中继续查找
    • 条件返回 TRUE
  • NOT EXISTS关键字表示如果不存在某种条件,则返回TRUE,否则返回FALSE
题目:查询公司管理者的 employee_id last_name job_id department_id 信息
方式一:
SELECT employee_id, last_name, job_id, department_id
FROM employees e1
WHERE EXISTS ( SELECT *
FROM employees e2
WHERE e2 .manager_id =
e1 .employee_id );
方式二:自连接
SELECT DISTINCT e1 .employee_id , e1 .last_name , e1 .job_id , e1 .department_id
FROM employees e1 JOIN employees e2
WHERE e1 .employee_id = e2 .manager_id ;
方式三:
SELECT employee_id,last_name,job_id,department_id
FROM employees
WHERE employee_id IN (
SELECT DISTINCT manager_id
FROM employees
);
题目:查询 departments 表中,不存在于 employees 表中的部门的 department_id department_name
SELECT department_id, department_name
FROM departments d
WHERE NOT EXISTS ( SELECT 'X'
FROM employees
WHERE department_id = d .department_id );

 

4.4 相关更新

UPDATE table1 alias1
SET column = ( SELECT expression
FROM table2 alias2
WHERE alias1 .column = alias2 .column );
使用相关子查询依据一个表中的数据更新另一个表的数据。
题目:在 employees 中增加一个 department_name 字段,数据为员工对应的部门名称
# 1
ALTER TABLE employees
ADD (department_name VARCHAR2( 14 ));
# 2
UPDATE employees e
SET department_name = ( SELECT department_name
FROM departments d
WHERE e .department_id = d .department_id );

4.4 相关删除

DELETE FROM table1 alias1
WHERE column operator ( SELECT expression
FROM table2 alias2
WHERE alias1 .column = alias2 .column );
使用相关子查询依据一个表中的数据删除另一个表的数据。
题目:删除表 employees 中,其与 emp_history 表皆有的数据
DELETE FROM employees e
WHERE employee_id in
( SELECT employee_id
FROM emp_history
WHERE employee_id = e .employee_id );

5. 抛一个思考题

问题: 谁的工资比 Abel 的高?
解答:
# 方式 1 :自连接
SELECT e2 .last_name ,e2 .salary
FROM employees e1,employees e2
WHERE e1 .last_name = 'Abel'
AND e1. `salary` < e2. `salary`
# 方式 2 :子查询
SELECT last_name,salary
FROM employees
WHERE salary > (
SELECT salary
FROM employees
WHERE last_name = 'Abel'
);
问题: 以上两种方式有好坏之分吗?
解答: 自连接方式好!
题目中可以使用子查询,也可以使用自连接。一般情况建议你使用自连接,因为在许多 DBMS 的处理过程中,对于自连接的处理速度要比子查询快得多。
可以这样理解:子查询实际上是通过未知表进行查询后的条件判断,而自连接是通过已知的自身数据表进行条件判断,因此在大部分 DBMS 中都对自连接处理进行了优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/449630.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机组成原理 作业5

作业5 题量: 21 满分: 100 作答时间:03-23 09:45至03-29 23:59 91.7分 一. 单选题&#xff08;共11题&#xff0c;35分&#xff09; 1. (单选题, 3分)计算机的存储器采用分级存储体系的主要目的是________。 A. 便于读写数据B. 便于系统…

NetSuite Sublist解释

今朝汇编一下Sublist主题的知识点以备忘。 2个数据源类型 Related Record - 以Saved Search建立的关联记录&#xff1b;Child Record - 父子表&#xff1b; 1. Related Record Saved Search关键点 这种形式的Sublist是利用Saved Search作为Sublist的数据源&#xff0c;将某…

【群智能算法】一种改进的白鲸优化算法IBWO【Matlab代码#17】

文章目录 1. 原始BWO算法1.1 勘探阶段1.2 开发阶段1.3 鲸落阶段 2. 改进白鲸优化算法2.1 Tent映射种群初始化2.2 反向学习策略 3. 部分代码展示4. 仿真结果展示5. 资源获取 1. 原始BWO算法 BWO算法的种群初始化和大多数智能算法相同&#xff0c;即随机产生搜索空间中的若干候选…

python协程实战

协程简介 协程(Coroutine)又称微线程、纤程&#xff0c;协程不是进程或线程&#xff0c;其执行过程类似于 Python 函数调用&#xff0c;Python 的 asyncio 模块实现的异步IO编程框架中&#xff0c;协程是对使用 async 关键字定义的异步函数的调用; 一个进程包含多个线程,类似…

MySQL学习笔记第三天

第04章 运算符 1.算术运算符 算术运算符主要用于数学运算&#xff0c;其可以连接运算符前后的两个数值或表达式&#xff0c;对数值或表达式进行加&#xff08;&#xff09;、减&#xff08;-&#xff09;、乘&#xff08;*&#xff09;、除&#xff08;/&#xff09;和取模&a…

13、go并发编程

目录 一、并发模型二、MPG并发模型三、Goroutine的使用1 - 协程使用2 - panic与defer 四、channel的同步与异步‘’1 - 同步与异步channel2 - 关闭channel 五、并发安全性1 - 资源竞争2 - 原子操作3 - 读写锁4 - 容器的并发安全 六、多路复用1 - 阻塞I/O2 - 非阻塞I/O3 - 多路复…

差分(一维+二维)

类似于数学中的求导和积分&#xff0c;差分可以看成前缀和的逆运算。 前缀和我们是求原数组的前缀和&#xff0c;这里是把原数组当成前缀和&#xff0c;构造一个差分数组来运算 以一维为例&#xff0c;如原数组为a[1],a[2],a[3]...a[n] 前缀和的思想是构造st[1]a[1],st[2]a[…

【C++】vector的使用

文章目录 1. 主要结构2. 构造函数与复制重载3. 迭代器4. 容量相关1.容量读取2.容量修改 5. 数据访问6. 数据修改1. 尾插尾删2.任意位置的插入删除 7.其他接口 在之前我们学习了string的使用与模拟实现&#xff0c;在参考文档中可以发现&#xff0c;vector和string以及其他的容器…

I/O 设备

CPU有两种方法访问IO设备 都是基于PMIO的&#xff0c;Port Mapped I/O 给IO总线上的寄存器编号&#xff0c;CPU向IO总线请求写入或读取数据 &#xff08;x86&#xff09;给特定的内存地址对应上目标IO设备&#xff0c;当CPU读取这段内存的时候&#xff0c;就会把访问转发给IO…

微服务 - Consul服务注册中心

概述 上篇说到构建良好的架构&#xff0c;依托于基础设施建设(自动化测试、自动化部署、服务监控&#xff0c;服务发现、配置中心等等)&#xff0c;决定成败的往往是基础设施建设&#xff0c;所以从搭建一个注册中心和配置中心开始我们新一阶段的启程。 注册中心 注册中心选型…

Cordic算法原理详解

目录 坐标旋转分析 Cordic算法原理 应用举例1&#xff1a;求sin值与cos值 应用举例2&#xff1a;求反正切值 cosθ的还原补偿 坐标旋转数字计算机CORDIC(COordinate Rotation DIgital Computer)算法&#xff0c;通过移位和加减运算&#xff0c;能递归计算常用函数值&#…

《Netty》从零开始学netty源码(四十一)之PoolChunk.runsAvail

runsAvail runsAvail用于记录long型的指针值&#xff0c;是一个LongPriorityQueue数组&#xff0c;LongPriorityQueue的结构如下&#xff1a; array数组用于存储handle的值&#xff0c;其中下标对应SizeClasses中pageIdx&#xff0c;size为array数组的大小&#xff0c;size的大…

1.13|1.14|1.15|1.6、GDB调试

1.13|1.14|1.15|1.6、GDB调试 1.13、GDB调试&#xff08;1&#xff09;&#xff0c;GDB调试&#xff08;2&#xff09;1. 什么是GDB2. 准备工作3. GDB命令—启动、推出、查看代码实际操作①用list查看代码 1.15、GDB调试&#xff08;3&#xff09;1. GDB命令—断点操作实际操作…

Redis 快速上手 Java 增删改查(包含 RedisTemplateConfig 的编写)

一&#xff1a;Redis 数据类型 先了解 redis 的五种基本数据类型。 String 字符串类型&#xff1a;name: "value1"List 列表&#xff1a;names: ["value1", "value2", "value2"]Set 集合&#xff1a;names: ["value1", &qu…

多源迁移学习网络补充知识用于具有不可见故障的机器智能诊断

**摘要&#xff1a;**当前基于深度迁移学习的故障诊断的大多数成功需要两个假设&#xff1a;1&#xff09;源机器的健康状态集合应当与目标机器的健康状态集合重叠;2&#xff09;目标机器样本的数量跨健康状态平衡。然而&#xff0c;这样的假设在工程场景中是不现实的&#xff…

【闲聊杂谈】HTTPS原理详解

HTTPS和HTTP的区别 HTTP虽然使用极为广泛, 但是却存在不小的安全缺陷, 主要是其数据的明文传送和消息完整性检测的缺乏, 而这两点恰好是网络支付, 网络交易等新兴应用中安全方面最需要关注的。 关于 HTTP的明文数据传输, 攻击者最常用的攻击手法就是网络嗅探, 试图从传输过程…

Redis高可用高性能缓存的应用系列06 - 热Key,大Key,并发竞争解决方案

概述 终于迎来了Redis系列的尾声&#xff0c;本文针对Redis常遇到的热Key&#xff0c;大Key&#xff0c;并发竞争解决方案进行介绍。 热Key 什么是热key?当一个key的访问量明显大于其他key的时候&#xff0c;他就可以被称为热key。 热Key带来的问题 热key占用大量的CPU资…

黑马在线教育数仓实战7

1. hive的相关的优化 1.1 hive的相关的函数(补充说明) if函数: 作用: 用于进行逻辑判断操作语法: if(条件, true返回信息,false返回信息) 注意: if函数支持嵌套使用 nvl函数: 作用: null值替换函数格式: nvl(T value, T default_value) COALESCE函数 作用: 非空查找函数:格式…

Windows安装GPU环境CUDA、深度学习框架Tensorflow和Pytorch

Windows安装GPU环境CUDA、深度学习框架Tensorflow和Pytorch 1、未安装CUDA使用tensorflow报错 import tensorflow as tf2022-03-06 15:14:38.869955: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library cudart64_110.dll; dl…

Django | 一文完美解决admin增加新用户只有用户名密码和确认密码的问题

文章目录 如图所示&#xff0c;下面给出解决方案&#xff1a; 如果您使用 使用 Django 默认的后台管理界面添加用户时&#xff0c;只看到了三个字段&#xff08;通常是 username、password和 repassword&#xff09;&#xff0c;那么可以通过定义 add_fieldsets 属性来增加更多…