五、DQL语言学习
5.8 子查询
5.8.1 含义
出现在其他语句中的select语句,称为子查询或内查询
外部的查询语句,称为主查询或外查询
5.8.2 分类
- 按子查询出现的位置:
- select后面:仅仅支持标量子查询
- from后面:支持表子查询
- where或having后面:支持标量子查询、列子查询、行子查询
- exists后面(相关子查询):表子查询
- 按结果集的行列数不同:
- 标量子查询(单行子查询)
- 列子查询(多行子查询)
- 行子查询(多行多列)
特点:
- 子查询放在小括号内
- 子查询一般放在条件的右侧
- 标量子查询,一般搭配着单行操作符(> < >= <= = <>)使用
- 列子查询,一般搭配着多行操作符(in any/some all)使用
标量子查询
要求:左后返回的结果为一行一列
案例1:谁的工资比Abel高?
# 1. 查询Abel的工资
# select salary from employees where last_name='Abel';
# 2. 查询员工的信息,满足salary>1的结果
select * from employees where salary>(select salary from employees where last_name='Abel');
案例2:返回job_id与141号员工相同,salary比143号员工多的员工,姓名、job_id和工资
# 1.查询141号员工的job_id
# select job_id from employees where employee_id=141
# 2.查询143号员工的salary
# select salary from employees where employee_id=143
# 3.查询员工的姓名,job_id和工资,要求job_id= 1的结果 并且salary>2的结果
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
)
案例3:返回公司工资最少的员工的last_name,job_id和salary
# 1.查询公司的最低工资
# select min(salar) from employees
# 2.查询last_name,job_id和salary,要求salary=1的结果
select last_name,job_id,salary
from employees
where salary=(select min(salary) from employees)
案例4:查询最低工资>50号部门最低工资的部门id和其最低工资
# 1.查询50号部门的最低工资
-- select min(salary) from employees where department_id=50
# 2.查询每个部门的最低工资
-- select min(salary),department_id
-- from employees
-- group by department_id
# 3.在2.结果基础上筛选,满足min(salary)>1的结果
select min(salary),department_id
from employees
group by department_id
having min(salary)>(
select min(salary)
from employees
where department_id=50
)
列子查询(多行子查询)
- 返回多行
- 使用多行比较操作符 | 操作符 | 含义 | | —- | —- | | IN / NOT IN | 等于列表中的任意一个 | | ANY | SOME | 和子查询返回的某一个值比较 | | ALL | 和子查询返回的所有值比较 |
案例1:返回location_id是1400或1700的部门中所有员工姓名
# 1. 查询location_id是1400或1700的部门编号
-- select distinct department_id
-- from departments
-- where location_id in (1400,1700)
--
# 2. 查询员工姓名,要求部门编号是1的结果中的某一个
select last_name
from employees
where department_id in(
select distinct department_id
from departments
where location_id in (1400,1700)
)
案例2:返回其他工种中比job_id为’IT_PROG’工种任一工资低的员工号、姓名、job_id以及salary
# 1.查询job_id为`IT_PROG`部门任一工资
-- select distinct salary
-- from employees
-- where job_id='IT_PROG'
# 2.查询员工号、姓名、job_id以及salary,salary<(1的结果)的任意一个
select last_name,employee_id,job_id,salary
from employees
where salary<any(
select distinct salary
from employees
where job_id='IT_PROG'
)
and job_id<>'IT_PROG';
案例3:返回其他部门中比job_id为’IT_PROG’部门所有工资都低的员工大的员工号、姓名
、job_id以及salary
# 1.查询job_id为`IT_PROG`部门任一工资
-- select distinct salary
-- from employees
-- where job_id='IT_PROG'
# 2.查询员工号、姓名、job_id以及salary,salary<(1的结果)的所有
select last_name,employee_id,job_id,salary
from employees
where salary<all(
select distinct salary
from employees
where job_id='IT_PROG'
)
and job_id<>'IT_PROG';
行子查询(多列子查询)
案例:查询员工编号最小并且工资最高的员工信息
按照之前的思路解法
# 1.查询最小的员工编号
-- select min(employee_id)
-- from employees
# 2.查询最高工资
-- select max(salary)
-- from employees
# 3.查询员工信息
select *
from employees
where employee_id=(
select min(employee_id)
from employees
)
and salary=(
select max(salary)
from employees
)
现在换用列子查询:
# 列子查询有其局限性,操作符只能为同一个,下面的就为 = 操作符
select *
from employees
where (employee_id,salary)=(
select min(employee_id),max(salary)
from employees
)
5.8.5 select后面
select后面仅支持标量子查询
案例:查询每个部门的员工个数
select d.*, (select count(*)
from employees e
where e.department_id=d.department_id
) as 个数
from departments d;
5.8.6 from后面
案例:查询每个部门的平均工资的工资等级
# 1.查询每个部门的平均工资
-- select avg(salary),department_id
-- from employees
-- group by department_id;
# 2.连接1的结果和job_grades表,筛选平均工资
select ag_dep.*,g.grade_level
from (
select avg(salary) ag,department_id
from employees
group by department_id
) as ag_dep
inner join job_grades g
on ag_dep.ag between lowest_sal and highest_sal;
5.8.7 exists后面(相关子查询)
exis
用来查询结果是否存在:
/*语法:
exists(完整的查询语句)
结果:
1或0
*/
SELECT EXISTS(SELECT employee_id FROM employees) AS 是否存在;
案例1:查询有员工的部门名
# 方法1:使用exists来实现
SELECT department_name
FROM departments d
WHERE EXISTS(
SELECT *
FROM employees e
WHERE d.`department_id`=e.`department_id`
);
# 方法2:使用in关键字来实现
SELECT department_name
FROM departments d
WHERE d.`department_id` IN(
SELECT department_id
FROM employees
);
案例2:查询没有女朋友的男神信息
# 方法1:使用in关键字
USE `girls`;
SELECT bo.*
FROM boys bo
WHERE bo.id NOT IN(
SELECT boyfriend_id
FROM beauty
);
# 方法2:使用exists关键字
SELECT bo.*
FROM boys bo
WHERE NOT EXISTS(
SELECT boyfriend_id
FROM beauty b
WHERE bo.`id`=b.`boyfriend_id`
);
5.8.8 子查询测试
- 查询和Zlotkey 相同部门的员工姓名和工资
- 查询工资比公司平均工资高的员工的员工号,姓名和工资
- 查询各部门中工资比本部门平均工资高的员工的员工号, 姓名和工资
- 查询和姓名中包含字母 u 的员工在相同部门的员工的员工号和姓名
- 查询在部门的location_id 为1700 的部门工作的员工的员工号
- 查询管理者是King 的员工姓名和工资
查询工资最高的员工的姓名,要求 first_name 和 last_name 显示为一列,列名为 姓.名
5.8.9 子查询经典案例题目
查询工资最低的员工信息: last_name, salary
- 查询平均工资最低的部门信息
- 查询平均工资最低的部门信息和该部门的平均工资
- 查询平均工资最高的 job 信息
- 查询平均工资高于公司平均工资的部门有哪些?
- 查询出公司中所有 manager 的详细信息.
- 各个部门中 最高工资中最低的那个部门的 最低工资是多少
- 查询平均工资最高的部门的 manager 的详细信息: last_name, department_id, email, salary
5.9 分页查询
应用场景:我们的数据一次加载不完,所以要分成几页来显示,类似如下
```sql /*语法: select 查询列表 from 表 [join type join 表2 on 连接条件 where 筛选条件 group by 分组字段] limit offset,size;
offset 要显示条目的起始索引(起始索引从0开始) size 要显示的条目个数 */
**案例1**:查询前5条员工的信息
```sql
SELECT * FROM employees LIMIT 0,5;
# 或者
SELECT * FROM employees LIMIT 5;
案例2:查询第11条-第25条的信息
SELECT * FROM employees LIMIT 10,15;
案例3:有奖金的员工信息,并且工资较高的前10名显示出来
SELECT *
FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY salary DESC
LIMIT 10;
5.10 Union联合查询
联合查询:将多条查询语句联合起来
应用场景:要用到的结果来自于多个表,且多个表之间没有连接关系,但是所要查询的信息是一样的。
/*语法:
查询语句1
union
查询语句2
union
...
*/
案例:查询部门编号>90或邮箱包含a的员工信息
# 方法1:在where后改变条件
SELECT *
FROM employees
WHERE email LIKE '%a%'
OR department_id>90;
# 方法2:使用连接查询
SELECT * FROM employees WHERE email LIKE '%a%'
UNION
SELECT * FROM employees WHERE department_id>90;
注意:
UNION
关键字会将结果进行去重,所以有时候为了避免去重,需要使用UNION ALL
关键字- 要求多条查询语句的查询列数是一致的
- 要求多条查询语句的查询的每一列的类型和顺序最好一致