MySQL子查询知识总结
- MySQL子查询知识总结
- 一、分类
- 1. 按子查询出现的位置
- 2. 按结果集的行列数不同
- 二、WHERE 或 HAVING 后面
- 1. 特点
- 2. 标量子查询
- ① WHERE 后的标量子查询
- ② WHERE 后的列子查询
- ③ WHERE 后的行子查询
- ④ SELECT 后的子查询
- ⑤ FROM 后的子查询
- ⑥ EXISTS 后的子查询 (相关子查询)
MySQL子查询知识总结
一、分类
1. 按子查询出现的位置
① SELECT 后面:
仅支持标量子查询
② FROM 后面:
支持表子查询
③ (重点) WHERE 或 HAVING 后面:
※ 标量子查询 (单行)
※ 列子查询 (多行)
行子查询
④ EXISTS 后面 (相关子查询):
表子查询
2. 按结果集的行列数不同
① 标量子查询 (结果集一行一列)
② 列子查询 (结果集一列多列)
③ 行子查询 (结果集一行多列)
④ 表子查询 (结果集一般为多行多列)
二、WHERE 或 HAVING 后面
1. 特点
① 子查询放在小括号里
② 子查询一般放在条件的右侧
③ 标量子查询一般搭配单行操作符使用
如 > < = >= <= <>
④ 列子查询一般搭配多行操作符使用
如 IN, ANY, SOME, ALL等
⑤ 子查询的执行优先于主查询
2. 标量子查询
① WHERE 后的标量子查询
# 案例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, 143号员工的salary
SELECT
job_id
FROM
employees
WHERE
employee_id = 141;
SELECT
salary
FROM
employees
WHERE
employee_id = 143;
# 第二步: 套娃
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;
# 第二步: 套娃
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
department_id,
MIN(salary)
FROM
employees
GROUP BY
departments_id
HAVING
MIN(salary) > (
SELECT
MIN(salary)
FROM
employees
WHERE
department_id = 50
);
② WHERE 后的列子查询
操作符 | 含义 |
(重点) IN / NOT IN | 等于列表中的任意一个 |
ANY | SOME | 和子查询返回的任意值比较 |
ALL | 和子查询返回的所有值比较 |
# 列子查询 (多行子查询)
# 案例1: 返回 location_id 是 1400 或者 1700 的部门中所有员工姓名
# 第一步: 子查询 查询部门
SELECT DISTINCT
department_id
FROM
departments
WHERE
location_id IN (1400, 1700);
# 第二步: 主查询
SELECT
last_name
FROM
employees
WHERE
department_id IN ( # 'IN' 可改为 '= ANY', 'NOT IN' 可改为 '<> ALL'
SELECT DISTINCT
department_id
FROM
departments
WHERE
location_id IN (1400, 1700)
);
# 案例2: 返回其他工种中比 job_id 为 'IT_PROG' 工种任一工资低的员工的员工号、姓名、job_id 以及 salary
# 第一步: 子查询
SELECT DISTINCT
salary
FROM
employees
WHERE
job_id = 'IT_PROG';
# 第二步: 主查询
SELECT
employee_id,
last_name,
job_id,
salary
FROM
employees
WHERE
salary < ANY (
SELECT DISTINCT
salary
FROM
employees
WHERE
job_id = 'IT_PROG'
)
AND
job_id <> 'IT_PROG';
# 或者用聚合函数
SELECT
employee_id,
last_name,
job_id,
salary
FROM
employees
WHERE
salary < (
SELECT DISTINCT
MAX(salary)
FROM
employees
WHERE
job_id = 'IT_PROG'
)
AND
job_id <> 'IT_PROG';
# 案例3: 返回其他部门中比 job_id 为 'IT-PROG' 部门所有工资都低的员工的员工号、姓名、job_id 以及 salary
# 将上题的ANY换成ALL
/* 注意: 'IN' 可改为 '= ANY', 'NOT IN' 可改为 '<> ALL' */
③ WHERE 后的行子查询
# 行子查询 (一行多列 或 多行多列)
# 案例: 查询员工编号最小并且工资最高的员工信息
# 第一步: 查询最小编号
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
);
④ SELECT 后的子查询
# 案例1: 查询每个部门的员工个数
SELECT
d.*, (
SELECT
COUNT(*)
FROM
employees e
WHERE
e.department_id = d.department_id
) AS 个数
FROM
departments d;
# 案例2: 查询员工数为102的部门名
# 方法一: 连接查询
SELECT
department_name
FROM
departments d
INNER JOIN
employees e
ON
d.department_id = e.department_id
WHERE
e.department_id = 102;
# 方法二: 行子查询
SELECT (
/* 方法一整体套进来, 其实没什么用 */
) AS 部门名;
/* 注意: select后仅支持标量子查询 */
⑤ FROM 后的子查询
USE myemployees;
# FROM 后的子查询
# 案例: 查询每个部门的平均工资的工资等级
# 第一步: 分组查询
SELECT
department_id,
AVG(salary)
FROM
employees
GROUP BY
department_id;
# 第二步: 子查询
SELECT
ag_dep.*,
g.grade_level
FROM
(
SELECT
department_id,
AVG(salary) AS ag
FROM
employees
GROUP BY
department_id
) AS ag_dep
INNER JOIN
job_grades g
ON ag_dep.ag
BETWEEN lowest_sal AND highest_sal;
⑥ EXISTS 后的子查询 (相关子查询)
# EXISTS 后的子查询 (相关子查询)
/*
语法:
exists(完整的查询语句)
结果为 0 或 1 代表 无 或 有;
*/
# 案例1: 查询有部门的员工名和部门名
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 方法
USE girls;
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 be
WHERE
bo.id = be.boyfriend_id
);