9. 子查询
作者:互联网
9.1 子查询使用场景
# 查询比Abel工资高的人
# 第一步先查询Abel的工资
SELECT salary
FROM employees
WHERE last_name = "Abel";
# 结果是11000
# 用第一步的查询结果查询工资比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 e2.salary > e1.salary;
子查询
通过子查询将两步查询变成一步
# 子查询实现
SELECT last_name, salary
FROM employees
WHERE salary > (SELECT salary FROM employees WHERE last_name = "Abel");
9.2 单行子查询
单行子查询:子查询中只返回一个数值
操作符 | 含义 |
---|---|
= | equal to |
> | greater than |
>= | greater than or equal to |
< | less than |
<= | less than or equal to |
<> | not equal to |
子查询简单练习
# 查询工资大于149号员工工资的员工的信息
SELECT last_name, salary
FROM employees
WHERE salary > (SELECT salary FROM employees WHERE employee_id = 149);
# 返回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,manager_id,department_id
# 这里是一个多行子查询
# 不成对查询
SELECT employee_id, manager_id, department_id
FROM employees
WHERE manager_id IN
(SELECT manager_id FROM employees WHERE employee_id IN (141, 174))
AND department_id IN
(SELECT department_id FROM employees WHERE employee_id IN (141, 174))
AND employee_id NOT IN(141, 174);
# 成对查询
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);
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);
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;
子查询中的空值问题
子查询中如果查询结果如果没有值或者结果为null,那么会出现结果是是空值。
SELECT last_name, job_id
FROM employees
WHERE job_id =
(SELECT job_id
FROM employees
WHERE last_name = 'Haas');
子查询返回空行
非法使用子查询
单行运算符后面用多行子查询,会报错
SELECT employee_id, last_name
FROM employees
WHERE salary =
(SELECT MIN(salary)
FROM employees
GROUP BY department_id);
/*
Subquery returns more than 1 row
*/
9.3 多行子查询
常用多行比较运算符
操作符 | 含义 |
---|---|
IN | 等于列表中任意一个 |
ANY | 需要和单行比较操作符一起使用,和子查询返回的某一个值比较 |
ALL | 需要和单行比较操作符一起使用,和子查询返回的所有值比较 |
SOME | 实际上是ANY的别名,作用相同,一般常使用ANY |
多行子查询简单练习
# 题目:返回其它job_id中比job_id为‘IT_PROG’部门任一工资低的员工的员工号、姓名、job_id 以及salary
SELECT employee_id, last_name, job_id, salary
FROM employees
WHERE salary < ANY(SELECT salary FROM employees WHERE job_id = "IT_PROG")
AND job_id <> "IT_PROG";
# 题目:返回其它job_id中比job_id为‘IT_PROG’部门所有工资都低的员工的员工号、姓名、job_id以及salary
SELECT employee_id, last_name, job_id, salary
FROM employees
WHERE salary < ALL(SELECT salary FROM employees WHERE job_id = "IT_PROG")
AND job_id <> "IT_PROG";
# 题目:查询平均工资最低的部门id
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);
# 这里多表查询的时候,新创建的表必须要有别名,同时列名最好有对应的别名
空值问题
多行子查询也有空值问题
# 这里会出现返回空行
SELECT last_name
FROM employees
WHERE employee_id NOT IN (
SELECT manager_id FROM employees
);
9.4 相关子查询
子查询的执行依赖外部查询,通常情况下都是因为子查询中的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重新计算一次,这样的子查询称为关联子查询。
例如图中的子查询就对主查询的数据进行了使用。
相关子查询简单练习
# 题目:查询员工中工资大于本部门平均工资的员工的last_name,salary和其department_id
# 相关子查询
SELECT last_name,salary,department_id
FROM employees e
WHERE e.salary >
(SELECT AVG(salary) FROM employees e_sal WHERE e_sal.department_id = e.department_id);
# 在FROM中使用子查询
SELECT last_name,salary,e.department_id
FROM employees e, (SELECT department_id, AVG(salary) avg_sal FROM employees GROUP BY department_id) avg_sal
WHERE e.department_id = avg_sal.department_id AND
e.salary > avg_sal.avg_sal;
# 题目:查询员工的id,salary,按照department_name 排序
# ORDER子查询
SELECT employee_id,salary
FROM employees e
ORDER BY (
SELECT department_name
FROM departments d
WHERE e.`department_id` = d.`department_id`
);
# 联表查询
SELECT e.employee_id, e.salary
FROM employees e LEFT JOIN departments d
ON e.department_id = d.department_id
ORDER BY d.department_name;
# 题目:若employees表中employee_id与job_history表中employee_id相同的数目不小于2,输出这些相同id的员工的employee_id,last_name和其job_id
SELECT e.employee_id,e.last_name,e.job_id
FROM employees e
WHERE 2 <= (SELECT COUNT(*) FROM job_history WHERE employee_id = e.employee_id);
EXISTS与NOT EXISTS关键词
- 关联子查询通常也会和 EXISTS操作符一起来使用,用来检查在子查询中是否存在满足条件的行。
- 如果子查询中不存在满足条件的行
- 条件返回FALSE
- 继续在子查询中查找
- 如果在子查询中存在满足条件的行
- 不在子查询中继续查找
- 条件返回TRUE
- NOT EXISTS 关键字表示如果不存在某种条件,则返回TRUE,否则返回FALSE
# 查询公司管理者的employee_id,last_name,job_id,department_id信息
# 方式一:
SELECT DISTINCT e1.employee_id,e1.last_name,e1.job_id,e1.department_id
FROM employees e1
WHERE e1.employee_id IN (SELECT DISTINCT manager_id FROM employees);
# 方式二:自连接
SELECT DISTINCT e1.employee_id,e1.last_name,e1.job_id,e1.department_id
FROM employees e1 JOIN employees e2
ON e1.employee_id = e2.manager_id;
# 方式三:
SELECT e1.employee_id,e1.last_name,e1.job_id,e1.department_id
FROM employees e1
WHERE EXISTS (SELECT * FROM employees e2 WHERE e2.manager_id = e1.employee_id);
# 查询departments表中,不存在于employees表中的部门的department_id和department_name
SELECT d.department_id,d.department_name
FROM departments d
WHERE NOT EXISTS (SELECT 'X' FROM employees e WHERE e.department_id = d.department_id);
相关更新
UPDATE table1 alias1
SET column = (SELECT expression FROM table2 alias2 WHERE alias1.column = alias2.column);
使用相关子查询依据一个表中的数据更新另一个表的数据
# 在employees中增加一个department_name字段,数据为员工对应的部门名称
UPDATE employees e
SET department_name = (SELECT department_name FROM departments d WHERE e.department_id = d.department_id);
相关删除
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);
9.5 自联接和子查询效率问题
问题:谁的工资比Abel高
# 子查询实现
SELECT last_name, salary
FROM employees
WHERE salary > (SELECT salary FROM employees WHERE last_name = "Abel");
# 用自联接来实现
SELECT e2.last_name, e2.salary
FROM employees e1, employees e2
WHERE e1.last_name = "Abel" AND e2.salary > e1.salary;
自连接的方式好
子查询实际上是通过未知表进行查询后的条件判断,自连接是通过已知的自身数据表进行条件判断,因此在大部分DBMS中都对自连接处理进行了优化
9.6 练习
#1.查询和Zlotkey相同部门的员工姓名和工资
SELECT e.last_name,e.salary
FROM employees e
WHERE e.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 > (SELECT MIN(salary)
FROM employees
WHERE job_id = "SA_MAN");
#4.查询和姓名中包含字母u的员工在相同部门的员工的员工号和姓名
SELECT employee_id, last_name
FROM employees
WHERE department_id IN (SELECT DISTINCT department_id
FROM employees
WHERE last_name LIKE "%u%")
#5.查询在location_id为1700的部门工作的员工的员工号
SELECT employee_id
FROM employees
WHERE department_id IN (SELECT DISTINCT department_id
FROM departments
WHERE location_id = 1700)
#6.查询管理者是King的员工姓名和工资
SELECT last_name, salary
FROM employees
WHERE manager_id IN (SELECT employee_id
FROM employees
WHERE last_name = "King");
#7.查询工资最低的员工信息: last_name, salary
SELECT last_name, salary
FROM employees
WHERE salary = (SELECT MIN(salary)
FROM employees);
# 8.查询平均工资最低的部门信息
# 方式一(平均工资中找出最小的平均工资)
SELECT *
FROM departments
WHERE department_id IN (SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (
SELECT MIN(dep_avgsal) FROM (SELECT AVG(salary) dep_avgsal
FROM employees
GROUP BY department_id) avg_sal));
# 方式二(平均工资小于等于所有平均工资即为最小)
SELECT *
FROM departments
WHERE department_id IN (SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) <= ALL(SELECT AVG(salary)
FROM employees
GROUP BY department_id));
# 方式三(求平均工资最低用排序)
SELECT *
FROM departments
WHERE department_id IN (SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id
ORDER BY avg_sal LIMIT 0,1));
# 方式四(等值连接)
SELECT d1.*
FROM departments d1, (SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id
ORDER BY avg_sal LIMIT 0,1)) d2
WHERE d1.department_id = d2.department_id;
#9.查询平均工资最低的部门信息和该部门的平均工资(相关子查询)
# 方式一 MIN找出工资最低
SELECT d.*, (SELECT AVG(salary) FROM employees e WHERE d.department_id = e.department_id)
FROM departments d
WHERE department_id in (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) dep_avgsal));
# 方式二 AVG <= ALL(平均工资)找出最低工资
SELECT d.*, (SELECT AVG(salary) FROM employees e WHERE d.department_id = e.department_id)
FROM departments d
WHERE department_id in (SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) <= ALL(
SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id));
# 方式三 Limit找出平均工资最高
SELECT d.*, (SELECT AVG(salary) FROM employees WHERE department_id = d.department_id)
FROM departments d
WHERE d.department_id IN (SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id
ORDER BY avg_sal LIMIT 0,1));
# 方式四 Limit找出平均工资最高(等值连接)
SELECT d1.*, d2.avg_sal
FROM departments d1, (SELECT department_id, AVG(salary) avg_sal
FROM employees
GROUP BY department_id
HAVING avg_sal = (SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id
ORDER BY avg_sal LIMIT 0,1)) d2
WHERE d1.department_id = d2.department_id;
#10. 查询平均工资最高的 job 信息
# 方式一 Limit找出平均工资最高
SELECT *
FROM jobs
WHERE job_id IN (SELECT job_id
FROM employees
GROUP BY job_id
HAVING AVG(salary) = (SELECT AVG(salary) avg_sal
FROM employees
GROUP BY job_id ORDER BY avg_sal DESC LIMIT 0, 1));
# 方式二 MAX找出平均工资最高
SELECT *
FROM jobs
WHERE job_id IN (SELECT job_id
FROM employees
GROUP BY job_id
HAVING AVG(salary) = (SELECT MAX(avg_sal)
FROM (SELECT AVG(salary) avg_sal
FROM employees
GROUP BY job_id) job_avgsal));
# 方式三 AVG >=找出平均工资最高
SELECT *
FROM jobs
WHERE job_id IN (SELECT job_id
FROM employees
GROUP BY job_id
HAVING AVG(salary) >= ALL(SELECT AVG(salary) avg_sal
FROM employees
GROUP BY job_id));
#11. 查询平均工资高于公司平均工资的部门有哪些?
SELECT e.department_id
FROM employees e
WHERE e.department_id IS NOT NULL
GROUP BY e.department_id
HAVING AVG(e.salary) > (SELECT AVG(salary) FROM employees);
#12. 查询出公司中所有 manager 的详细信息
# 方式一联表查询或者等值连接
SELECT DISTINCT m.*
FROM employees m JOIN employees e
ON m.employee_id = e.manager_id;
SELECT DISTINCT m.*
FROM employees m, employees e
WHERE m.employee_id = e.manager_id;
# 方式二 子查询
SELECT m.*
FROM employees m
WHERE m.employee_id IN (SELECT manager_id FROM employees);
# 方式三 相关子查询
SELECT m.*
FROM employees m
WHERE EXISTS (SELECT * FROM employees e WHERE e.manager_id = m.employee_id);
#13. 各个部门中 最高工资中最低的那个部门的最低工资是多少?
# 方式一用limit找出最高工资最低的部门(作为条件)
SELECT employee_id, MIN(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary) = (SELECT MAX(salary) max_sal
FROM employees
GROUP BY department_id ORDER BY max_sal LIMIT 0, 1);
# 方式二 用limit找出最高工资最低的部门(作为联表查询)
SELECT employee_id, MIN(salary)
FROM employees e, (SELECT department_id
FROM employees
GROUP BY department_id ORDER BY MAX(salary) LIMIT 0, 1) dep_maxsal
WHERE e.department_id = dep_maxsal.department_id;
# 方式三 MAX找出最高工资
SELECT employee_id, MIN(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary) = (SELECT MIN(max_sal)
FROM (SELECT MAX(salary) max_sal
FROM employees
GROUP BY department_id) dep_sal);
# 方式四 MAX() >= 其他的MAX找出最高工资
SELECT employee_id, MIN(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary) <= ALL(SELECT MAX(salary)
FROM employees
GROUP BY department_id);
#14. 查询平均工资最高的部门的 manager 的详细信息: last_name, department_id, email, salary
# 方式一 LIMIT找出最高工资对应的department_id,利用department_id找到对应的manager_id
SELECT last_name, department_id, email, salary
FROM employees
WHERE employee_id IN (SELECT DISTINCT manager_id FROM departments d,
(SELECT department_id FROM employees GROUP BY department_id ORDER BY AVG(salary) DESC LIMIT 0, 1) avg_sal
WHERE d.department_id = avg_sal.department_id);
# 方式二 用AVG(salary) >= ALL找出最高工资
SELECT last_name, department_id, email, salary
FROM employees
WHERE employee_id IN (SELECT DISTINCT manager_id FROM departments d
WHERE department_id IN (SELECT department_id FROM employees
GROUP BY department_id
HAVING AVG(salary) >= ALL(SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id ORDER BY avg_sal)));
# 方式二 用MAX(salary)找出最高工资
SELECT last_name, department_id, email, salary
FROM employees
WHERE employee_id IN (SELECT DISTINCT manager_id FROM departments d
WHERE department_id IN (SELECT department_id FROM employees
GROUP BY department_id
HAVING AVG(salary) = (SELECT MAX(avg_sal) FROM (SELECT AVG(salary) avg_sal
FROM employees
GROUP BY department_id ORDER BY avg_sal) dep_avgsal)));
#15. 查询部门的部门号,其中不包括job_id是"ST_CLERK"的部门号
SELECT department_id
FROM departments
WHERE department_id NOT IN (SELECT DISTINCT department_id FROM employees WHERE job_id = "ST_CLERK");
SELECT d.department_id
FROM departments d
WHERE NOT EXISTS (SELECT * FROM employees e WHERE e.department_id = d.department_id AND e.job_id = "ST_CLERK")
#16. 查询所有没有管理者的员工的last_name
SELECT last_name
FROM employees e1
WHERE NOT EXISTS (SELECT * FROM employees e2 WHERE e1.manager_id = e2.employee_id);
#17.查询员工号、姓名、雇用时间、工资,其中员工的管理者为 'De Haan'
# 子查询
SELECT employee_id, last_name, hire_date, salary
FROM employees
WHERE manager_id = (SELECT employee_id FROM employees WHERE last_name = "De Haan");
# 等值连接
SELECT e1.employee_id, e1.last_name, e1.hire_date, e1.salary
FROM employees e1, employees e2
WHERE e2.`employee_id` = e1.manager_id
AND e2.last_name = 'De Haan';
#18.查询各部门中工资比本部门平均工资高的员工的员工号, 姓名和工资(相关子查询)
# 相关子查询
SELECT e.employee_id, e.last_name, e.salary
FROM employees e
WHERE e.salary > (SELECT AVG(salary) FROM employees e1 WHERE e1.department_id = e.department_id);
# 方式二
SELECT e.employee_id, e.last_name, e.salary
FROM employees e, (SELECT department_id, AVG(salary) avg_sal FROM employees GROUP BY department_id) e1
WHERE e.department_id = e1.department_id AND e.salary > e1.avg_sal;
#19.查询每个部门下的部门人数大于 5 的部门名称(相关子查询)
SELECT department_name
FROM departments d
WHERE 5 < (SELECT COUNT(*) FROM employees e WHERE e.department_id = d.department_id);
#20.查询每个国家下的部门个数大于 2 的国家编号(相关子查询)
SELECT country_id
FROM locations l
WHERE 2 < (SELECT COUNT(*) FROM departments d WHERE l.location_id = d.location_id);
标签:salary,employees,查询,department,WHERE,id,SELECT 来源: https://www.cnblogs.com/jiangblog/p/16449314.html