前言
最近这几天由于一些个人原因,停更了一段时间,感到十分抱歉。回顾了下自己之前写的内容,感觉在SQL语句这块写的还是有些粗枝大叶,所以重新补充下。SQL的基础内容请参考前面的内容,本篇重点介绍下SQL语句中的子查询分类以及使用方法。
广告时间:
HaloDB业内首次创造性的提出插件式内核架构设计,通过配置的方式,适配不同的应用场景,打造全场景覆盖的能力,满足企业大部分数据存储处理需求。从而消除数据孤岛,降低系统复杂度,保护企业既有投资,降低企业成本。同时支持x86、arm等异构平台之间的混合部署。
如果有对我们的产品感兴趣的朋友可以通过主页的联系方式与我取得联系,获取license来安装体验,目前已经开通HaloDB吐槽群,欢迎来喷,进群请私聊我获取。
一、子查询的基本概念
说到这里,关于子查询我想分为什么是子查询,子查询有哪些应用场景,子查询有哪些优缺点来给大家介绍。
1.1、什么是子查询:
在SQL语言中,一个SELECT-FROM-WHERE语句称为一个查询块。当获得一个查询的答案需要多个步骤的操作,首先必须创建一个查询来确定用户不知道但包含在数据库中的值,将一个查询块嵌套在另一个查询块的WHERE字句或HAVING短语的条件中查询块称为子查询或内层查询。上层的查询块曾为父查询或外层查询。子查询的结果作为输入传递回“父查询”或“外部查询”。父查询将这个值结合到计算中,以便确定最后的输出。
上面是百度给出的标准解释,但是我觉得简单来考虑,可以用子查询就是嵌套在SQL查询语句中的查询。这样说更容易理解一些。
1.2、子查询的几种类型:
子查询的类别大致可以按照按位置和结果来分类,子查询可以根据不同的标准进行分类,以下是几种主要的分类方式及其特点:
(a)按位置分类
- WHERE子查询:子查询放在WHERE子句中,作为外部查询的条件使用。这类子查询通常返回单值,用于比较操作(如=, <, >, IN等)。
- FROM子查询:子查询放在FROM子句中,其结果作为临时表供外部查询进一步查询。这要求子查询返回多行多列,形成一个表结构。
- SELECT子查询:直接在SELECT列表中使用,返回单列单值或多列多值,用于计算或展示额外的数据。
- HAVING子查询:类似于WHERE子查询,但用在HAVING子句中,用于对分组后的结果进行条件过滤。
- ORDER BY子查询 / GROUP BY子查询:虽然不常见,但在某些数据库系统中,子查询也可用于ORDER BY或GROUP BY子句中,以提供排序或分组的依据。
(b)按结果分类
- 标量子查询:返回单一值的查询,通常用于比较操作,如IN、=、>等。
- 列子查询:返回一列数据的查询,每个外部查询的行都会与之比较或结合。
- 行子查询:返回一行多列数据的查询,通常与外部查询的特定行进行匹配。
- 表子查询:返回多行多列数据,作为外部查询的数据源,相当于一个临时表。
二、测试用例:
2.1、创建测试表的SQL语句
CREATE TABLE Employees (
EmployeeID INT PRIMARY KEY,
FirstName VARCHAR(50),
LastName VARCHAR(50),
Department VARCHAR(50),
HireDate DATE
);
2.2、插入测试数据:
INSERT INTO Employees (EmployeeID, FirstName, LastName, Department, HireDate)
VALUES (1, 'John', 'Doe', 'IT', '2020-01-01'),
(2, 'Jane', 'Smith', 'HR', '2019-06-8'),
(3, 'Alex', 'Johnson', 'Finance', '2018-12-7'),
(4, 'Emily', 'Brown', 'IT', '2021-03-15'),
(5, 'Michael', 'Davis', 'HR', '2020-09-10'),
(6, 'Sarah', 'Miller', 'Finance', '2017-02-20');
2.3、假设增加薪资和经理ID列以支持其他查询示例:
ALTER TABLE Employees ADD Salary DECIMAL(10, 2);
ALTER TABLE Employees ADD ManagerID INT;
UPDATE Employees SET Salary = 75000 WHERE EmployeeID = 1;
UPDATE Employees SET Salary = 60000 WHERE EmployeeID = 2;
UPDATE Employees SET Salary = 80000 WHERE EmployeeID = 3;
UPDATE Employees SET Salary = 70000 WHERE EmployeeID = 4;
UPDATE Employees SET Salary = 65000 WHERE EmployeeID = 5;
UPDATE Employees SET Salary = 78000 WHERE EmployeeID = 6;
UPDATE Employees SET ManagerID = 3 WHERE EmployeeID IN (4, 5);
另一张测试表:
CREATE TABLE student(no int primary key, student_name varchar(40), age int, class_no int);
INSERT INTO student VALUES(1, '张三', 14, 1);
INSERT INTO student VALUES(2, '吴二', 15, 1);
INSERT INTO student VALUES(3, '李四', 13, 2);
INSERT INTO student VALUES(4, '吴三', 15, 2);
INSERT INTO student VALUES(5, '王二', 15, 3);
INSERT INTO student VALUES(6, '李三', 14, 3);
INSERT INTO student VALUES(7, '吴二', 15, 4);
INSERT INTO student VALUES(8, '张四', 14, 4);
三、不同类型的子查询示例:
3.1、select子查询测试用例:
使用SQL语句查询列出所有员工的姓名,并附上他们所在部门的平均薪资,SQL语句如下:
SELECT FirstName, LastName,
(SELECT AVG(Salary) FROM Employees e2 WHERE e2.Department = Employees.Department) AS AvgDeptSalary
FROM Employees;
查询结果如下:

3.2、from子查询测试用例:
使用SQL查询找出每个部门薪资最高的员工的姓名、姓氏及薪资:
SELECT e1.FirstName, e1.LastName, e1.Salary
FROM Employees e1
JOIN (
SELECT Department, MAX(Salary) AS MaxSalary
FROM Employees
GROUP BY Department
) e2
ON e1.Department = e2.Department AND e1.Salary = e2.MaxSalary;
查询结果如下:

3.3、WHERE子查询测试用例:
使用SQL语句查询找出所有薪资高于其所在部门平均薪资的员工的姓名和薪资。
SELECT FirstName, LastName
FROM Employees
WHERE Department = (SELECT Department FROM Employees WHERE Department = 'IT');

3.4、EXISTS子查询测试用例:
使用SQL查询出所有有下属的经理的姓名:
SELECT FirstName, LastName
FROM Employees e1
WHERE EXISTS (
SELECT 1
FROM Employees e2
WHERE e2.ManagerID = e1.EmployeeID
);

还有一些按照谓词分类的子查询使用另一个测试表来展示(测试用例来自唐成老师所著的书籍《PostgreSQL修炼之道从小工到专家》)我偷懒了
3.5、带有谓词IN的子查询:
查询初二一版的学生记录
SELECT * FROM student WHERE class_no in (select no FROM class where class_name = '初二(1)班');
为了大家方便理解,我单独执行子查询语句。

3.6、带有ANY(SOME)或ALL谓词的子查询
同样是找出初二一班学生的信息,我们还可以换一种方式使用带有ANY(SOME)或ALL谓词的子查询来实现
SELECT * FROM student WHERE class_no = (SELECT no FROM class c WHERE class_name = '初二(1)班');

最后:
希望这篇关于子查询的类别和使用方法能对你有所帮助,要想学好SQL语句离不开自己的大量的练习,感谢大家一直以来的点赞和关注,虽然是慢工,但是不是什么细活,我们下期见~




