数据库-进阶7-子查询

进阶7-子查询

# 进阶7:子查询
/*
	含义:
		出现在其他语句中的 select 语句,称为子查询或内查询
		外部的查询语句,称为主查询或外查询
	分类:
		按子查询的位置:
			select 后面
				仅仅支持标量子查询
			from 后面
				支持表子查询
			where 或 having 后面      ⭐
				标量子查询(单行)√
				列子查询(多行)  √
				行子查询(使用较少)
			exists 后面(相关子查询)
				表子查询
		按结果集的行列数不同:
			标量子查询(结果集只有一行一列)
			列子查询(结果集只有一列多行)
			行子查询(结果集有多行多列)
			表子查询(结果集一般为多行多列)
*/
#一、where 或 having 后面
	#1.标量子查询(单行子查询)
	#2.列子查询(多行查询)
	
	#3.行子查询(多行多列查询)
	
	#特点:
		# ① 子查询放在小括号内
		# ② 子查询一般放在条件的右侧
		# ③ 标量子查询 ,一般搭配着单行操作符来使用
			# > < >= <= = <>
		# 列子查询:一般搭配着多行操作符的使用
			# in、any/some、all
		# ④ 子查询的执行优先于主查询的执行,主查询的条件用到了子查询的结果	
			
		#1.标量子查询
			#案例1:谁的工资比 Abel 高
				# ① 查询 Abel 的工资
					SELECT salary
					FROM employees
					WHERE last_name = 'Abel';
				# ② 查询员工的信息,满足 salary > ① 结果
					SELECT e.*
					FROM employees
					WHERE salary > (
						SELECT salary
						FROM employees
						WHERE last_name = 'Abel';
					);
			#案例2:返回 job_id 与 141 员工相同,salary 比 143 号员工多的员工 姓名,job_id 和工资
				# ① 查询 141 号员工的 job_id
					SELECT job_id
					FROM employees
					WHERE employee_id = 141
				# ② 查询 143 号员工的 salary
					SELECT salary
					FROM employees
					WHERE employee_id = 143
				# ③ 查询员工的姓名,job_id 和工资,要求 job_id = ① 并且 salary > ②
					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
				# ① 查询公司的 最低工资
					SELECT MIN(salary)
					FROM employees
				# ② 查询 last_name,job_id,salary 要求 工资 = ①
					SELECT last_name,job_id,salary
					FROM employees
					WHERE salary = (
						SELECT MIN(salary)
						FROM employees
					);
			#案例4:查询最低工资大于 50 号部门最低工资的部门的部门 id 和其最低工资
				# ① 查询 50 号部门的最低工资
					SELECT MIN(salary)
					FROM employees
					WHERE department_id = 50;
				# ② 查询每个部门的最低工资
					SELECT MIN(salary),department_id
					FROM employees
					GROUP BY department_id;
				# ③ 在 ② 基础上筛选,满足 min(salary) > ①
					SELECT MIN(salary),department_id
					FROM employees
					GROUP BY department_id
					HAVING MIN(salary) > (
						SELECT MIN(salary)
						FROM employees
						WHERE department_id = 50
					);
			# 非法使用标量子查询
				SELECT MIN(salary),department_id
				FROM employees
				GROUP BY department_id
				HAVING MIN(salary) > (
					SELECT salary
					FROM employees
					WHERE department_id = 250
				);
		#2.列子查询(多行子查询)
			#案例1:返回 location_id 是 1400 或 1700 的部门中的所有员工姓名
				# ① 查询 location_id 是 1400 或 1700 的部门的部门编号
					SELECT department_id 
					FROM departments
					WHERE department_id IN(1400,1700);
				# ② 查询员工姓名,要求部门号是 ① 列表中的某一个
					SELECT last_name
					FROM employees
					WHERE department_id IN(
						SELECT department_id 
						FROM departments
						WHERE department_id IN(1400,1700);
					);
			# 案例2:返回其他部门中比 job_id 为 'IT_PROG' 部门任意一工资低的员工的员工名、姓名、job_id 以及 salary
				# ① 查询 job_id 为 'IT_PROG' 部门任意工资
					SELECT DISTINCT salary
					FROM employees
					WHERE job_id = 'IT_PROG'
				# ② 查询员工名、姓名、job_id 以及 salary,salary < (①)的任意一个	
					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';
					# 或
					SELECT last_name,employee_id,job_id,salary
					FROM employees
					WHERE salary < (
						SELECT MAX(salary) 
						FROM employees
						WHERE job_id = 'IT_PROG'
					) AND job_id <> 'IT_PROG';
			#案例3:返回其他部门中比 job_id 为 'IT_PROG' 部门所有工资都低的员工  的员工号、姓名、job_id 以及 salary
				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';
				# 或
				SELECT last_name,employee_id,job_id,salary
				FROM employees
				WHERE salary < (
					SELECT MIN(salary)  
					FROM employees
					WHERE job_id = 'IT_PROG'
				) AND job_id <> 'IT_PROG';
		#3.行子查询(结果集一行多列或者多行多列)
			#案例1:查询员工编号最小并且工资最高的员工信息
					
				SELECT * 
				FROM employees
				WHERE employee_id,salary = (
					SELECT MIN(employee_id),MAX(salary)
					FROM employees;
				);	
			
				# ① 查询最小的员工编号
					SELECT MIN(employee_id)
					FROM employees
				# ② 查询最高工资
					SELECT MAX(salary)
					FROM employees
				# ③ 查询员工信息
					SELECT * 
					FROM employees
					WHERE employee_id = (
						SELECT MIN(employee_id)
						FROM employees
					) AND salary = (
						SELECT MAX(salary)
						FROM employees
					);
#二、select后面
/*
	仅仅支持标量子查询
*/
	#案例1:查询每个部门的员工个数
		SELECT d.*,(
			SELECT COUNT(*) 
			FROM employees e
			WHERE e.department_id = d.department_id
		) 个数
		FROM departments d;
	#案例2:查询员工号 = 102 的部门名
		SELECT (
			SELECT department_name
			FROM departments d
			INNER JOIN employees e
			ON d.department_id = e.department_id
			WHERE e.department_id = 102
		) 部门名;
#三、from 后面
/*
	要求子查询结果充当一张表,要求必须起别名
*/
	#案例:查询每个部门的平均工资的工资等级
		# ① 查询每个部门的平均工资
			SELECT AVG(salary),department_id
			FROM employees
			GROUP BY department_id
		# ② 连接 ① 的结果集和 job_grades 表,筛选条件平均工资 between lowest_sal and highest_sal
			
			SELECT ag_dep.*,g.grade_level
			FROM(
				SELECT AVG(salary) ag,department_id
				FROM employees
				GROUP BY department_id
			) ag_dep
			INNER JOIN job_grades g
			ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;
#四、exists 后面(相关子查询)
/*
	语法:
	exists(完整的查询语句)
	结果:
		1或0
*/
	SELECT EXISTS (SELECT employee_id FROM employees WHERE salary = 30000);
	#案例1:查询有员工的部门名
		#exists
		SELECT department_name
		FROM departments d
		WHERE EXISTS(
			SELECT *
			FROM employees e
			WHERE d.department_id =e.department_id
		);
		
		#in
		SELECT department_name
		FROM departments d 
		WHERE d.department_id IN(
			SELECT department_id
			FROM employees 
		);
	#案例2:查询没有女朋友的男神信息
		# in
		SELECT bo.*
		FROM boys bo
		WHERE bo.id NOT IN (
			SELECT boyfriend_id
			FROM beauty 
		);
		# exists
		SELECT bo.*
		FROM boys bo
		WHERE NOT EXISTS(
			SELECT boyfriend_id
			FROM beauy b
			WHERE bo.id = b.boyfriend_id	
		);
#例题1:查询和 Zlotkey 相同部门的员工姓名和工资
	# ① 查询 Zlotkey 的部门
		SELECT department_id
		FROM employees
		WHERE last_name = 'Zlotkey';
	# ② 查询部门号 = Zlotkey 的员工的姓名和工资
		SELECT last_name,salary
		FROM employees
		WHERE department_id = (
			SELECT department_id
			FROM employees
			WHERE last_name = 'Zlotkey';
		);
#例题2:查询工资比公司平均工资搞的员工的员工号,姓名和工资。
	# ① 查询平均工资
		SELECT AVG(salary)
		FROM employees
	# ② 查询工资 > ① 的员工号,姓名和工资。
		SELECT last_name,employee_id,salary
		FROM employees
		WHERE salary > (
			SELECT AVG(salary)
			FROM employees
		);
#例题3:查询各部门中工资比本部门平均工资高的员工的员工号,姓名和工资	
	# ① 查询各部门的平均工资
		SELECT AVG(salary),department_id
		FROM employees
		GROUP BY department_id;
	# ② 连接 ① 结果集和 employees 表,进行筛选
		SELECT last_name,employee_id,salary,department_id
		FROM employees e
		INNER JOIN (
			SELECT AVG(salary) ag,department_id
			FROM employees
			GROUP BY department_id;
		) ag_dep
		ON e.department_id = ag_dep.department_id
		WHERE salary > ag_dep.ag;
#例题4:查询和姓名中包含字母 u 的员工在相同部门的员工的员工号和姓名	
	# ① 查询和姓名中包含字母 u 的员工的部门
		SELECT DISTINCT department_id
		FROM employees
		WHERE last_name LIKE '%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 的部门工作的员工的员工号
	# ① 查询 location_id 为 1700 的部门
		SELECT DISTINCT department_id
		FROM departments
		WHERE location_id = 1700
	# ② 查询部门号 = ① 中任意一个的员工号
		SELECT employee_id
		FROM employees
		WHERE department_id i = ANY(
			SELECT DISTINCT department_id
			FROM departments
			WHERE location_id = 1700
		);
#例题6:查询管理者是 King 的员工姓名和工资
	# ① 查询姓名为 king 的员工编号
		SELECT employee_id
		FROM employees
		WHERE last_name = 'King'
	# ② 查询那个员工的 manager_id = ①
		SELECT last_name,salary
		FROM employees
		WHERE manager_id IN(
			SELECT employee_id
			FROM employees
			WHERE last_name = 'King'
		);
#例题7:查询工资最高的员工的姓名,要求 first_name 和 last_name 显示为一列,列名为 姓.名
	# ① 查询最高工资
		SELECT MAX(salary)
		FROM employees
	# ② 查询工资 = ① 的姓.名
		SELECT CONCAT(first_name,last_name) "姓.名"
		FROM employees
		WHERE salary = (
			SELECT MAX(salary)
			FROM employees
		);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值