ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

9. 子查询

2022-07-06 08:00:48  阅读:171  来源: 互联网

标签:salary employees 查询 department WHERE id SELECT


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 相关子查询

子查询的执行依赖外部查询,通常情况下都是因为子查询中的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重新计算一次,这样的子查询称为关联子查询。

image-20220701082241070

例如图中的子查询就对主查询的数据进行了使用。

相关子查询简单练习

# 题目:查询员工中工资大于本部门平均工资的员工的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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有