第九章 子查询
概念:子查询是指一个查询语句嵌套在另一个查询语句内部的查询, 这个特性从MySQL4.1就开始引入
SQL中子查询的使用大大增强了select查询的能力,因为很多时候查询需要从结果集中获取数据,或者需要
从同一个表中先计算得出一个数据结果,然后与这个数据结果进行比较。
子查询的分类:
角度1:从内查询返回的结果的条目数
单行子查询VS多行子查询
角度2:内查询是否被执行多次
相关子查询VS不相关子查询
SELECT last_name,salary
FROM employees
WHERE salary>(SELECT salary
FROM employees
WHERE last_name='Abel');
单行子查询的操作符
操作符
= equal to
> greater than
>= greater than or equal to
< less than
<= less than or equal to
<=> not equal to
题目:返回job_id与141号员工相同,salary比143号员工多的员工姓名,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,department_id
SELECT employee_id,department_id ,manager_id
FROM employees
WHERE manager_id=(SELECT manager_id FROM employees WHERE employee_id=141 OR employee_id=174 )
AND
department_id=(SELECT department_id FROM employees WHERE employee_id=141 OR employee_id=174)
AND
employee_id<>141 and employee_id<>174;
3.多行子查询
也称为集合比较子查询
内查询返回多行
使用多行比较操作
3.1多行比较操作符
IN 等于列表中的任意一个
ANY 需要和单行比较操作符一起使用,和子查询返回的某一个值比较
ALL 需要和单行比较操作符一起使用,和子查询返回的所有值比较
SOME 实际上是ANY的别名,作用相同,一般使用ANY
举例:
SELECT employee_id,last_name
FROM employees
WHERE salary
IN (SELECT MIN(salary) FROM employees GROUP BY department_id);
例题:返回其它job_id中比job_id为'IT_PROG'部门任一工资低的员工的员工号
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE job_id<>'IT_PROG'
AND salary <ANY(
SELECT salary
FROM employees
WHERE job_id='IT_PROG'
);
题目:查询平均工资最低的部门id
做了三层子查询
方式1:
SELECT department_id FROM employees
GROUP BY department_id
HAVING AVG(salary) IN
(
SELECT MIN(avg_salary)
FROM
(SELECT AVG(salary) as avg_salary FROM employees GROUP BY department_id) t_dept_avg_sal);
方式2:
SELECT department_id FROM employees
GROUP BY department_id
HAVING AVG(salary)<= ALL
(
SELECT AVG(salary) FROM employees GROUP BY department_id);
题目:查询平均工资最高的部门id
方式1:
SELECT department_id FROM employees
GROUP BY department_id
HAVING AVG(salary) IN
(
SELECT MAX(avg_max_salary)
FROM
(SELECT AVG(salary) as avg_max_salary FROM employees GROUP BY department_id)t_dept_max_sal);
方式2:
SELECT department_id FROM employees
GROUP BY department_id
HAVING AVG(salary)>=ALL(
SELECT AVG(salary) FROM employees GROUP BY department_id);
空值问题:
SELECT last_name
FROM employees
WHERE employee_id NOT IN(
SELECT manager_id FROM employees
)
4.相关子查询
4.1相关子查询的执行流程
如果子查询的执行依赖外部查询,通常情况下都是因为子查询中的表使用到了外部的表,并进行了条件关联,因此每执行一次外部查询,
子查询都要重新计算一次,这样的子查询就称之为关联子查询
相关子查询按照一行接一行的顺序执行,主查询的每一行都执行一次子查询
题目:查询员工中工资大于本部门平均工资的员工的last_name,salary和其department_id
SELECT last_name,salary,department_id FROM employees
WHERE salary >(SELECT AVG(salary) FROM employees )
SELECT last_name,salary,department_id
FROM employees e1
WHERE salary >(
SELECT AVG(salary)
FROM employees e2
WHERE department_id=e1.department_id
);
题目:查询员工的id,salary,按照department_name排序
SELECT employee_id,salary FROM employees e ORDER BY (
SELECT department_name FROM departments d WHERE d.department_id=e.department_id
) ASC;
结论;
在select 中,除了GROUP BY 和LIMIT之外,其他任何地方都可以用子查询
题目:若employees表中employees与job_history表中employee_id相同的数目
不小于2,输出这些相同id的员工的employee_id,last_name和其job_id
SELECT * FROM job_history;
SELECT employee_id,last_name,job_id
FROM employees e
WHERE 2<=(
SELECT COUNT(*) FROM job_history j
WHERE e.department_id= j.employee_id )
4.3EXISTS与NOT EXISTS 关键字
关联子查询通常也会和EXISTS操作符一起使用,用来检查在子查询中是否存在满足条件的行
如果在子查询中不存在满足条件的行:
条件返回false.
题目:查询公司管理者的employee_id,last_name,job_id,department_id信息
SELECT DISTINCT m.employee_id,m.last_name,m.job_id,m.department_id
FROM employees e JOIN employees m
ON e.manager_id =m.employee_id;
子查询练习:
子查询技巧:(1)从里往外(2)从外往里
1.查询和Zlotkey相同部门员工的姓名和工资
SELECT last_name,salary ,department_id
FROM employees
WHERE department_id =(
SELECT department_id
FROM employees
WHERE last_name='Zlotkey'
);
2.查询工资比公司平均工资高的员工号,姓名和工资
SELECT employee_id,last_name,salary
FROM employees
WHERE salary>(
SELECT AVG(salary)
FROM employees
);
3.选择工资大于所有job_id='SA_MAN'的员工的工资的员工的last_name,job_id,salary
SELECT last_name,job_id,salary
FROM employees
WHERE salary >ALL(
SELECT salary
FROM employees
WHERE job_id='SA_MAN'
);
4.查询和姓名中包含字母U的员工在相同部门的员工的员工号和姓名
SELECT last_name,employee_id
FROM employees
WHERE department_id IN(
SELECT DISTINCT department_id
FROM employees
WHERE last_name like '%u%'
);
5.查询在部门的location_id为1700的部门工作的员工的员工号
SELECT employee_id,last_name
FROM employees
WHERE department_id IN(
SELECT department_id
FROM departments
WHERE location_id =1700
);