MySQL子查询知识总结

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
);

注: 本文档查询使用的数据来源为尚硅谷

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

y孤狐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值