嵌套查询指在一个查询语句的某个部分嵌入一个子查询。
嵌套查询的执行过程遵循“先子查询、后外层查询”的逻辑。首先,子查询执行并返回一个结果集,可能是一个值、一行或多行数据。接着,外层查询使用子查询的结果继续对数据进行筛选或处理。通过这种方式,嵌套查询可以处理更复杂的逻辑,如多层条件过滤、数据对比等。
SELECT 列名
FROM 表名
WHERE 列名 比较运算符 (子查询);
先通过子查询返回结果,然后再通过比较运算符判断子查询返回的结果是否满足条件,满足条件的字段的记录,就会展示该记录被SELECT的字段。
SELECT column_name1
FROM table_name1
WHERE column_name2 比较运算符 (SELECT column_name3 FROM table_name2 WHERE condition);
- 比较运算符之后的 “(SELECT column_name3 FROM table_name2 WHERE condition)” 是作为子查询,执行SQL语句时,会先选出表table_name2中符合条件condition的记录的column_name3字段给外层查询。
- 当得到了子查询返回的column_name3字段,外层查询会先将表table_name1的所有记录的column_name2字段 通过比较运算符与这些返回的column_name3字段进行比较。
- 对于满足了比较运算符规则的column_name2字段的记录,会返回这些记录的column_name1字段。
=
:用于检查外层查询的某个列的值是否等于子查询返回的值。>
、<
、>=
、<=
:用于比较外层查询的列值与子查询结果之间的大小关系。IN
:用于检查外层查询的某个列值是否在子查询返回的一组结果中。ANY
/ SOME
:用于检查外层查询的列值是否满足子查询返回结果中的任意一个值的条件。ALL
:用于检查外层查询的列值是否满足子查询返回结果中的所有值的条件。注意:
ANY
/SOME和ALL
一般要结合>
、<
、>=
、<=来使用
4. ANY
/ SOME
运算符
SELECT name
FROM employees
WHERE salary > ANY (SELECT salary FROM employees WHERE department_id = 1);
5. ALL
运算符
SELECT name
FROM employees
WHERE salary > ALL (SELECT salary FROM employees WHERE department_id = 1);
语法结构:
SELECT 列名
FROM 表名
WHERE 列名 比较运算符 (子查询);
示例:
SELECT 姓名, 工资
FROM 员工
WHERE 工资 = (SELECT MAX(工资) FROM 员工);
解释:
(SELECT MAX(工资) FROM 员工)
返回员工表中的最高工资。IN
、ANY
、ALL
等)来将外层查询的字段与子查询返回的多个结果进行比较和匹配。语法结构:
SELECT 列名
FROM 表名
WHERE 列名 IN (子查询);
示例:
SELECT 姓名
FROM 员工
WHERE 部门编号 IN (SELECT 部门编号 FROM 部门 WHERE 城市 = '上海');
解释:
(SELECT 部门编号 FROM 部门 WHERE 城市 = '上海')
返回所有位于上海的部门编号,这是一组值。语法结构:
SELECT 列名
FROM 表名 AS 外层表
WHERE 列名 比较运算符 (SELECT 列名 FROM 子查询表 WHERE 子查询表.列名 = 外层表.列名);
示例:
SELECT 房屋编号, 价格
FROM 房屋 AS 可买房屋
WHERE 价格 > (SELECT AVG(价格)
FROM 房屋 AS 出售房屋
WHERE 出售房屋.城市 = 可买房屋.城市);
解释:
外层查询:
SELECT 房屋编号, 价格 FROM 房屋 AS 可买房屋
:房屋
表中检索每个房屋的编号和价格,并将 房屋
表赋予别名 可买房屋
。这个别名的作用是帮助区分外层查询和子查询中的相同表名,以便进行比较。这一步的目的是从所有房屋中找到符合特定条件的房屋。子查询:
(SELECT AVG(价格) FROM 房屋 AS 出售房屋 WHERE 出售房屋.城市 = 可买房屋.城市)
:
子查询的任务是计算当前房屋所在城市的平均房价。子查询也使用了 房屋
表,但被赋予了别名 出售房屋
,用于避免与外层查询中的 可买房屋
混淆。子查询的 WHERE
子句指定了只有那些与当前外层查询的房屋处于相同城市的房屋记录才会参与平均价格的计算。
执行过程:每次外层查询处理一条新的房屋记录时,子查询都会根据这条房屋记录的城市,动态地计算该城市中所有房屋的平均价格。也就是说,子查询依赖于外层查询中的房屋城市信息。因此,当外层查询遍历到某个房屋时,子查询会执行一次,计算出这个房屋所在城市的平均房价。
结果作用:子查询返回的是该城市的平均房价。这个值会用于外层查询的 WHERE
子句中,帮助判断当前房屋的价格是否高于其所在城市的平均房价。
整体逻辑:
子查询的动态执行:对于每一条外层查询的记录(即每一个房屋),子查询都会基于该房屋的城市重新计算城市的平均房价。比如,当外层查询正在处理北京的某个房屋时,子查询会检索所有位于北京的房屋,并计算这些房屋的平均价格。
条件比较:外层查询的 WHERE
子句会将当前房屋的价格与子查询返回的城市平均房价进行比较。如果当前房屋的价格高于该城市的平均房价,则该房屋的编号和价格会被返回。
语法结构:
SELECT 列名
FROM 表名
WHERE 列名 = (子查询);
示例:
SELECT 姓名
FROM 员工
WHERE 部门编号 = (SELECT 部门编号 FROM 部门 WHERE 部门名称 = '市场部');
解释:
(SELECT 部门编号 FROM 部门 WHERE 部门名称 = '市场部')
独立执行一次,返回市场部的部门编号。WHERE
、FROM
、SELECT
还是 HAVING
子句中。语法:
SELECT 列名
FROM 表名
WHERE 列名 比较运算符 (子查询);
使用场景:
示例:
SELECT employee_id, first_name, last_name
FROM employees
WHERE department_id = (
SELECT department_id
FROM departments
WHERE department_name = 'Sales'
);
子查询:
SELECT AVG(salary) FROM employees WHERE department_id = employees.department_id
用于计算每个员工所在部门的平均工资。WHERE department_id = employees.department_id
是关键部分,这里表示子查询是针对每个员工所在的部门来计算部门的平均工资。外层查询:
SELECT name, salary FROM employees
。WHERE
子句决定筛选条件,要求员工的 salary
大于子查询返回的值。执行过程:
语法:
SELECT 列名
FROM (子查询) AS 临时表
使用场景:
示例:
SELECT department_name, avg_salary
FROM (
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
) AS avg_department_salaries
JOIN departments ON avg_department_salaries.department_id = departments.department_id;
子查询:
SELECT department_id, salary FROM employees
提取所有员工的部门ID和工资,形成了一个虚拟表 dept_employees
。外层查询:
SELECT department_id, AVG(salary) AS average_salary, COUNT(*) AS num_employees
负责从 dept_employees
中对数据进行处理。AVG(salary)
计算每个部门的平均工资。COUNT(*)
计算每个部门的员工数。执行过程:
department_id
和 salary
列的临时表 dept_employees
。语法:
SELECT (子查询) AS 列名
FROM 表名;
使用场景:
示例:
SELECT employee_id, first_name, last_name,
(SELECT department_name
FROM departments
WHERE departments.department_id = employees.department_id) AS department_name
FROM employees;
子查询:
SELECT MAX(degree) FROM education WHERE education.employee_id = employees.id
用于查找与当前员工对应的最高学历。WHERE education.employee_id = employees.id
确保子查询与外层查询中的每个员工相匹配。外层查询:
SELECT name, ... FROM employees
检索所有员工的姓名。highest_degree
列使用子查询的结果作为额外的信息。执行过程:
highest_degree
。语法:
SELECT 列名
FROM 表名
GROUP BY 列名
HAVING 聚合函数 比较运算符 (子查询);
使用场景:
示例:
SELECT department_id
FROM employees
GROUP BY department_id
HAVING COUNT(*) > (SELECT AVG(employee_count) FROM (SELECT department_id, COUNT(*) AS employee_count FROM employees GROUP BY department_id) AS dept_counts);
子查询:
SELECT AVG(employee_count) FROM (SELECT department_id, COUNT(*) AS employee_count FROM employees GROUP BY department_id) AS dept_counts
首先计算每个部门的员工数量,然后计算这些数量的平均值。外层查询:
SELECT department_id FROM employees GROUP BY department_id
对员工按部门进行分组。HAVING COUNT(*) > ...
是一个过滤条件,用于过滤掉员工人数不满足条件的部门。执行过程:
HAVING
子句确保只返回那些员工数量大于平均值的部门。WHERE
子句中的嵌套查询:用于动态过滤外层查询的行,基于子查询的结果进行比较。FROM
子句中的嵌套查询:创建临时表,允许在外层查询中使用简化的数据集进行进一步的操作。SELECT
子句中的嵌套查询:生成动态列值,将子查询的结果直接应用到外层查询的每一行。HAVING
子句中的嵌套查询:用于基于聚合结果进行分组后的过滤,是处理复杂分组统计场景的有效手段。嵌套查询,尤其是复杂的嵌套查询,可能对数据库性能产生显著的影响。以下是影响性能的主要因素:
查询的重复执行:
索引的利用情况:
查询的复杂性:
使用 JOIN
替代子查询:
JOIN
查询。JOIN
查询通常更容易优化,数据库可以更高效地处理连接操作。例如,子查询可以被重写为 INNER JOIN
或 LEFT JOIN
,这通常会显著提高性能。索引优化:
WHERE
子句中出现的字段,如果有适当的索引,可以显著提高查询速度。避免相关子查询:
分解复杂查询: