六、 子查询
1 子查询介绍
1.1 什么是子查询
子查询是一个 SELECT 语句,它是嵌在另一个 SELECT 语句中的子句。
可以用组合两个查询的方法解决这个问题,放置一个查询到另一个查询中。内查询或子查询返回一个值给外查询或主查询。使用一个子查询相当于执行两个连续查询并且用第一个查询的结果作为第二个查询的搜索值。
1.2 子查询语法
• 子查询 (内查询) 在主查询之前执行一次
• 子查询的结果被用于主查询 (外查询)
可以将子查询放在许多的 SQL 子句中,包括:
• WHERE 子句
• HAVING 子句
• FROM 子句
2 使用子查询
2.1 使用子查询的原则
• 子查询放在圆括号中。
• 将子查询放在比较条件的右边。
• 在单行子查询中用单行运算符,在多行子查询中用多行运算符。
2.1.1 示例
谁的薪水比Abel高。用内连接实现:
select em.last_name,em.salary from employees abel,employees em
where abel.last_name = 'Abel' and em.salary > abel.salary;
用子查询实现:
select em.last_name,em.salary from employees em where em.salary >(
select m.salary from employees m where m.last_name ='Abel');
3 子查询的类型
• 单行子查询:子查询语句只返回一行的查询
• 多行子查询:子查询语句返回多行的查询
3.1 单行子查询
• 仅返回一行
• 使用单行比较符
主查询对子查询结果的单行比较运算符:
3.1.1 示例一
显示那些 job ID 与雇员 141 相同的雇员的名字与 job ID。
select em.last_name,em.job_id from employees em where em.job_id = (
select job_id from employees e where e.employee_id = 141);
3.1.2 示例二
显示 job ID 与雇员 141 相同,并且薪水 高于雇员 143 的那些雇员。
select e.last_name,e.job_id,e.salary from employees e where e.job_id = (
select em.job_id from employees em where em.employee_id = 141) and e.salary > (
select emp.salary from employees emp where emp.employee_id = 143);
3.2 在子查询中使用组函数
在子查询中也可使用组函数。
3.2.1 示例
显示所有其薪水等于最低薪水的雇员的 last name、job ID 和 salary。
select em.last_name,em.job_id,em.salary from employees em
where em.salary =(select min(salary) from employees);
3.3 带子查询的 HAVING 子句
可以在 WHERE 子句中使用子查询,也可以在 HAVING 子句中使用子查询。
3.3.1 示例
显示所有其最低薪水大于 部门 50 的最低薪水的部门号和最低薪水。
select em.department_id,min(em.salary) from employees em group by em.department_id having min(em.salary) > (
select min(e.salary) from employees e where e.department_id = 50);
子查询错误:使用子查询的一个常见的错误是单行子查询返回了多行。
3.5 多行子查询
• 返回多于一行
• 使用多行比较符
主查询对子查询的多行比较运算符
操作 | 含义 |
---|---|
in | 等于列表中的任何成员 |
any | 比较子查询返回的每一个值 |
all | 比较子查询返回的全部值 |
在条件中也可使用 NOT 取反。
3.6 在多行子查询中使用 IN 运算符
3.6.1 示例
查找各部门收入为部门最低的那些雇员。显示他们的名字,薪水以及部门 ID。
select e.last_name,e.department_id,e.salary from employees e where e.salary in(
select min(em.salary) from employees em group by em.department_id);
< ANY 意思是小于最大值。 >ANY 意思是大于最小值。
3.7.1 示例
显示工作岗位不是 IT_PROG 的雇员,并且这些雇员的的薪水少于 IT_PROG 工作岗位的雇员的 ID、名字、工作岗位和薪水。
select e.employee_id,e.last_name,e.job_id,e.salary from employees e where e.job_id <> 'IT_PROG' and e.salary < any (
select em.salary from employees em where em.job_id = 'IT_PROG') ;
<ALL 意思是小于最小值。>ALL 意思是大于最大值。
ANY 与 ALL 的区别:
ANY: >ANY 表示至少大于一个值,即大于最小值。
ALL: >ALL 表示大于每一个值,既大于最大值。
3.8.1 示例
显示那些薪水低于工作岗位 IT_PROG 的最低薪水,并且工作岗位不是 IT_PROG 的所有雇员。
4 子查询小结练习
4.1 写一个查询显示与 Zlotkey 在同一部门的雇员的 last name
和 hire date,结果中不包括 Zlotkey。
select em.last_name,em.hire_date from employees em where em.department_id = (
select e.department_id from employees e where e.last_name = 'Zlotkey');
4.2 创建一个查询显示所有其薪水高于平均薪水的雇员的雇员号和名字。按薪水的升序排序。
select em.employee_id,em.last_name from employees em where em.salary > (
select avg(salary) from employees) order by em.salary;
4.3 写一个查询显示所有工作在有任一雇员的名字中包含一个 u的部门的雇员的雇员号和名字。
select e.employee_id,e.last_name from employees e where e.department_id in(
select em.department_id from employees em where em.last_name like '%u%');
4.4 显示所有部门地点号 (department location ID ) 是 1700的雇员的 last name、department number 和 job ID。
select em.last_name,em.department_id,em.job_id from employees em where em.department_id in(
select d.department_id from departments d where d.location_id = 1700);
4.5 显示每个向 King 报告的雇员的名字和薪水。
select e.last_name,e.salary from employees e where e.manager_id in(
select em.employee_id from employees em where em.last_name = 'King');
4.6 显 示 在 Executive 部 门 的 每 个 雇 员 的 department number、last name 和 job ID。
select em.department_id,em.last_name,em.job_id from employees em where em.department_id = (
select d.department_id from departments d where d.department_name ='Executive');
4.7 查询显示所有收入高于平均薪水并且工作在有任一雇员的名字中带有一个 u 的部门的雇员的 employee numbers、last、names 和 salaries。
select emp.employee_id,emp.last_name,emp.salary from employees emp where emp.salary > (
select avg(salary) from employees) and emp.department_id in(
select em.department_id from employees em where em.last_name like '%u%');