声明:此MySQL基础学习源自尚硅谷。(推荐)b站官方链接:https://www.bilibili.com/video/BV1xW411u7ax?p=1
进阶7:子查询
| 含义: |
| 一条查询语句中又嵌套了另一条完整的select语句,其中被嵌套的select语句,称为子查询或内查询 |
| 外面的语句可以是insert、update、delete、select等,一般select作为外面语句较多 |
| 外面如果为select语句,则此语句称为外查询或主查询 |
| |
| 特点: |
| 1、子查询都放在小括号内 |
| 2、子查询可以放在from后面、select后面、where后面、having后面,但一般放在条件的右侧 |
| 3、子查询优先于主查询执行,主查询使用了子查询的执行结果 |
| 4、子查询根据查询结果的行数不同分为以下两类: |
| ① 单行子查询(标量子查询) |
| 结果集只有一行 |
| 一般搭配单行操作符使用:> < = <> >= <= |
| |
| 非法使用子查询的情况: |
| a、子查询的结果为一组值 |
| b、子查询的结果为空 |
| |
| ② 多行子查询(列子查询) |
| 结果集有多行 |
| 一般搭配多行操作符使用:any、all、in、not in |
| in: 属于子查询结果中的任意一个就行 |
| any和all往往可以用其他查询代替 |
| |
| 分类: |
| 按子查询出现的位置: |
| select后面: |
| 仅仅支持标量子查询 |
| |
| from后面: |
| 支持表子查询 |
| |
| where或having后面:★ |
| 标量子查询(单行) √ |
| 列子查询 (多行) √ |
| 行子查询(使用较少) |
| |
| exists后面(相关子查询) |
| 标量子查询 |
| 列子查询 |
| 行子查询 |
| 表子查询 |
| 按结果集的行列数不同: |
| 标量子查询(结果集只有一行一列) |
| 列子查询(结果集只有一列多行) |
| 行子查询(结果集有一行多列) |
| 表子查询(结果集一般为多行多列) |
| |
1.where或having后面
| 1、标量子查询(单行子查询) |
| 2、列子查询(多行子查询) |
| 3、行子查询(多列多行) |
| |
| 特点: |
| ①子查询放在小括号内 |
| ②子查询一般放在条件的右侧 |
| ③标量子查询,一般搭配着单行操作符使用 |
| |
| > < >= <= = <> |
| |
| 列子查询,一般搭配着多行操作符使用 |
| in/not in、any|some、all |
| |
| ④子查询的执行优先于主查询执行,主查询的条件用到了子查询的结果 |
1.标量子查询★
案例1:谁的工资比 Abel 高?
| #①查询Abel的工资 |
| SELECT salary |
| FROM employees |
| WHERE last_name = 'Abel' |
| |
| #②查询员工的信息,满足 salary>①结果 |
| SELECT * |
| 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,要求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.列子查询★
(多行子查询)
| 列子查询,一般搭配着多行操作符使用 |
| in / not in : 等于表中任意一个 (使用较多) |
| any | some : 和子查询返回的某一个值比较 |
| all : 和子查询返回的所有值比较 |
案例1:返回location_id是1400或1700的部门中的所有员工姓名
| #①查询location_id是1400或1700的部门编号 |
| SELECT DISTINCT department_id |
| FROM departments |
| WHERE location_id IN(1400,1700) |
| |
| #②查询员工姓名,要求部门号是①列表中的某一个 |
| |
| SELECT last_name |
| FROM employees |
| WHERE department_id <>ALL( |
| SELECT DISTINCT department_id |
| FROM departments |
| WHERE location_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.行子查询
(结果集一行多列或多行多列)(使用较少)
案例:查询员工编号最小并且工资最高的员工信息
| #①查询最小的员工编号 |
| 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 * |
| FROM employees |
| WHERE (employee_id,salary)=( |
| SELECT MIN(employee_id),MAX(salary) |
| FROM employees |
| ); |
2.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,e.department_id |
| FROM departments d |
| INNER JOIN employees e |
| ON d.department_id=e.department_id |
| WHERE e.employee_id=102 |
| |
| ) 部门名; |
| |
| SELECT |
| `department_name` |
| FROM |
| `departments` d |
| WHERE d.`department_id` = |
| (SELECT |
| `department_id` |
| FROM |
| `employees` |
| WHERE `employee_id` = 102) ; |
3.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; |
4.exists后面(相关子查询)
| 一般放在where后面,先查询主查询,子查询根据主查询结果条件判断是否满足。 |
| 语法: |
| exists(完整的查询语句) |
| 结果: |
| 1或0 |
| |
| 使用in可以替换。 |
| SELECT EXISTS(SELECT employee_id FROM employees WHERE salary=300000); |
案例1:查询有员工的部门名
in
| SELECT department_name |
| FROM departments d |
| WHERE d.`department_id` IN( |
| SELECT department_id |
| FROM employees |
| ) |
exists
| SELECT department_name |
| FROM departments d |
| WHERE EXISTS( |
| SELECT * |
| FROM employees e |
| WHERE d.`department_id`=e.`department_id` |
| |
| ); |
案例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 beauty b |
| WHERE bo.`id`=b.`boyfriend_id` |
| |
| ); |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步