Bootstrap

深入理解 SQL 中的子查询


本文将深入探讨 SQL 中子查询的基本用法、不同类型的子查询及其应用场景。

一、什么是子查询

子查询,也称为嵌套查询,是指将一个查询语句嵌套在另一个查询语句中,作为外部查询的一部分。子查询通常用来返回一个值、一个结果集,或者多个值供外部查询使用。

例如,下面的查询会在内层查询中获取 employee 表中最高薪水的员工,然后外层查询会根据这个薪水过滤出薪水高于该值的员工:

SELECT name, salary 
FROM employee
WHERE salary > (SELECT MAX(salary) FROM employee);

二、子查询的基本语法

SELECT column1, column2
FROM table1
WHERE column3 IN (SELECT column3 FROM table2 WHERE condition);

在上面的示例中:
外部查询从 table1 中选择数据。
内部查询从 table2 中选择数据,返回的结果供外部查询的 WHERE 子句使用。

三、数据准备

  • employee 表(员工信息表)
    在这里插入图片描述
  • department 表(部门信息表)
    在这里插入图片描述

四、子查询的分类

4.1 标量子查询

标量子查询是指返回单个值的子查询。它通常出现在 SELECT、WHERE 或 HAVING 子句中。标量子查询只返回一个列、一个值。

示例:
查询所有员工的名字和他们部门的名称(部门名称是通过标量子查询得到的):

SELECT name, 
       (SELECT department_name FROM department WHERE department_id = e.department_id) AS department_name
FROM employee e;

结果:
在这里插入图片描述

在此查询中,内层查询返回了每个员工所在部门的名称,外层查询通过使用该值来显示员工及其部门名称。

4.2 单行子查询

单行子查询是指返回一行数据的子查询。通常用于在 WHERE 或 HAVING 子句中进行比较操作。

示例:
查询 employee 表中薪水最高的员工信息:

SELECT name, salary
FROM employee
WHERE salary = (SELECT MAX(salary) FROM employee);

结果:
在这里插入图片描述

这里的子查询返回了薪水的最大值,并用于外部查询进行比较。

4.3 多行子查询

多行子查询是指返回多行数据的子查询。通常用于与 IN、ANY 或 ALL 操作符一起使用。

示例:
查询所有工资高于某一部门中最低工资的员工:

SELECT name, salary
FROM employee
WHERE salary > (SELECT MIN(salary) 
                 FROM employee 
                 WHERE department_id = 1);

结果:
在这里插入图片描述

在这个例子中,子查询返回了 department_id = 3 部门的最低工资,而外部查询返回了所有工资高于该值的员工。

4.4 关联子查询

关联子查询是指内层查询使用了外层查询中的字段,通常出现在 FROM 或 WHERE 子句中。这种子查询通常能根据外层查询的数据进行动态筛选。

示例:
查询部门中薪水高于该部门平均薪水的员工:

SELECT e.name, e.salary
FROM employee e
WHERE e.salary > (SELECT AVG(salary) 
                  FROM employee 
                  WHERE department_id = e.department_id);

结果:
在这里插入图片描述

在这个查询中,内层查询是根据外层查询中每个员工的 department_id 来计算该部门的平均薪水,从而筛选出薪水高于该平均值的员工。

五、子查询的应用场景

5.1 子查询与 WHERE 子句

子查询常常用来在 WHERE 子句中限制结果。例如,查询 employee 表中工资高于某一部门中最低工资的所有员工:

SELECT name, salary
FROM employee
WHERE salary > (SELECT MIN(salary) 
                FROM employee
                WHERE department_id = 3);

5.2 子查询与 SELECT 子句

子查询也可以出现在 SELECT 子句中,用于选择计算或聚合的结果。例如,查询每个员工的名字以及所在部门的平均薪水:

SELECT name, 
       (SELECT AVG(salary) FROM employee WHERE department_id = e.department_id) AS department_avg_salary
FROM employee e;

5.3 子查询与 FROM 子句

子查询还可以作为表使用,即放在 FROM 子句中。此时,子查询的结果集充当外层查询的表。

示例:
查询每个部门的员工数量:

SELECT department_id, COUNT(*)
FROM (SELECT DISTINCT department_id FROM employee) AS department_list
GROUP BY department_id;

结果:
在这里插入图片描述

在此示例中,内层子查询首先返回了所有不同的 department_id,外层查询则对其进行分组并计算每个部门的员工数量。

六、性能优化与注意事项

  • 避免不必要的嵌套查询: 子查询可能会影响性能,特别是当子查询返回大量数据时。尽量避免不必要的多层嵌套查询,考虑使用 JOIN 操作来替代。
  • 使用 EXISTS 替代 IN: 如果子查询返回大量数据,使用 EXISTS 可能比 IN 更有效。EXISTS 通常在判断是否存在某个条件时效率更高。
  • 索引: 子查询在查询过程中可能会多次执行,建议对相关字段创建索引,以提高查询性能。
  • 避免大量数据的返回: 如果子查询的数据量非常大,考虑分页或限制返回的行数,避免造成性能问题。

子查询的使用不仅使得查询更简洁,同时也增强了 SQL 查询的表达能力,是进行数据处理时不可或缺的工具。
在这里插入图片描述

;