SQL进阶应用:子查询与聚合函数详解
在 SQL 的高级应用中,子查询和聚合函数是处理复杂数据逻辑的重要工具。子查询利用嵌套结构实现多层次的条件判断,而聚合函数则用于数据的统计分析。两者的结合能够有效应对多维度的数据筛选与统计需求。本文将详细介绍子查询的不同类型、聚合函数的应用方法以及实际操作技巧,帮助读者掌握复杂查询的构建方法。
一、子查询:嵌套查询的灵活运用
子查询(即嵌套查询)是指在一个查询语句内部嵌入另一个完整的查询。其中,外部查询被称为“主查询”,内部查询被称为“子查询”。子查询可以作为条件、数据来源或计算字段,根据其与主查询的关系,可以分为简单子查询和相关子查询。
1. 简单子查询:独立的嵌套条件
简单子查询的执行不依赖于主查询的结果,可以独立运行,其结果通常用作主查询的筛选条件。根据返回结果的数量,简单子查询可以进一步划分为单值子查询和多值子查询。
(1)单值子查询:返回单一结果的子查询
当子查询返回唯一值时,可以与主查询中的比较运算符(如:、
、
、
、
)配合使用,适用于“与某个基准值进行比较”的场景。
示例 1: 查询欧洲人均GDP高于英国的国家
解析: 子查询独立计算英国的人均GDP(),主查询以此为基准,筛选出欧洲范围内人均GDP更高的国家。
示例 2: 查询人口数量介于英国和德国之间的国家
解析: 通过两个单值子查询分别获取英国和德国的人口数量,主查询使用和
筛选出人口数量在这两个国家之间(即区间筛选)的国家。
(2)多值子查询:返回多个结果的子查询
当子查询返回多行结果时,需要与、
、
等关键字配合使用,适用于“与多个值进行比较”的场景。
:判断字段是否在子查询结果列表中(等同于多个
);
:字段需满足与子查询结果中的任一值的比较条件;
:字段需满足与子查询结果中的所有值的比较条件。
示例: 查询GDP高于欧洲所有国家的国家(排除GDP为空的情况)
解析: 子查询返回欧洲所有国家的GDP(非空值),主查询通过筛选出GDP高于欧洲所有国家的国家,
确保满足“大于每一个值”的条件。
2. 相关子查询:依赖外部查询的动态筛选
相关子查询与主查询存在字段关联,其执行依赖于主查询的每一行数据——主查询每遍历一行,子查询就会根据当前行的字段值重新计算一次。这种特性使得相关子查询特别适合“按组筛选极值”或“关联条件判断”的场景。
(1)查询每组的最大值/最小值
示例: 查找每个大陆中面积最大的国家
解析: 主查询遍历表的每一行(别名
),对于每行的
(大陆),子查询(别名
)计算该大陆的最大面积(
);主查询通过
筛选出每个大陆中面积等于该大陆最大值的国家,最终得到各大陆面积最大的国家列表。
(2)查询每组的特定排序值
示例: 按字母顺序列出每个大洲的第一个国家(名称最小的国家)
解析: 子查询通过计算每个大陆中国家名称的最小值(按字母排序),主查询筛选出名称等于该最小值的国家,实现“每组首字母国家”的查询。
(3)使用
筛选关联数据
是一个逻辑判断关键字,用于检查子查询是否返回结果:如果子查询返回至少一行数据,
为
;反之,则为
。常与
结合使用,实现“不存在满足条件的关联数据”的筛选。
示例: 查找所有国家人口均≤2500万的大陆,并返回这些大陆的国家
解析: 主查询遍历每个国家(),子查询检查该国家所在的大陆(
)是否存在人口超过2500万的国家(
);
表示“不存在这样的国家”,即该大陆所有国家人口均≤2500万,最终返回这些大陆的所有国家。
二、聚合函数与分组查询
聚合函数用于对一组数据进行统计计算,如求和、计数、求平均值等,常与配合使用以实现“按组统计”,再通过
对分组结果进行二次筛选。
1. 常用聚合函数
| 函数 | 作用 | 说明 |
|---|---|---|
| 统计非NULL值的行数 | ||
| 统计所有行数(包括NULL) | ||
| 统计去重后的非NULL值行数 | 忽略重复值 | |
| 计算数值字段的总和 | 自动忽略NULL值 | |
| 计算数值字段的平均值 | 公式: |
|
| 查找字段的最大值 | 支持数值、字符串(按字符编码)、日期 | |
| 查找字段的最小值 | 支持数值、字符串(按字符编码)、日期 |
SQL中的字段操作与统计
1. 查找字段的最小值
此操作用于找出特定字段中的最小值。
2. 按字段分组统计
GROUP BY
此功能用于将数据根据指定的字段进行分组,分组后聚合函数的计算范围从整个表格缩小到每个分组内。
语法:
SELECT 分组字段, 聚合函数(字段)
FROM 表名
[WHERE 筛选条件] -- 分组前筛选行
GROUP BY 分组字段; -- 按指定字段分组
示例 1:统计每个大陆中人口≥1000 万的国家数量
SELECT continent, COUNT(name) AS country_count -- 按大陆分组,统计国家数量
FROM world
WHERE population >= 10000000 -- 先过滤人口≥1000万的国家(分组前筛选)
GROUP BY continent; -- 按大陆分组
解析:
WHERE population >= 10000000
- 首先筛选出人口达到标准的国家;
GROUP BY continent - 然后将结果按照大陆进行分组;
COUNT(name) - 最后统计每个分组内的国家数量(非NULL,等效于计数)。
nameCOUNT(*)
注意:
GROUP BY 后只能出现分组字段或聚合函数,不能直接使用非分组字段(否则会导致多值对应单值的逻辑错误)。例如,以下语句是错误的:-- 错误示例:SELECT中出现非分组字段name
SELECT continent, name, COUNT(name)
FROM world
GROUP BY continent;
3. 筛选分组后的结果
HAVING
此功能用于对已分组的数据结果进行进一步筛选,与
WHERE 的主要区别在于:
作用于分组前的原始行,不能使用聚合函数;WHERE
作用于分组后的结果,可以直接使用聚合函数。HAVING
示例:筛选总人口≥1 亿的大陆
SELECT continent
FROM world
GROUP BY continent -- 先按大陆分组
HAVING SUM(population) >= 100000000; -- 对分组后的总人口筛选
解析:
- 首先将所有国家按大陆分组;
GROUP BY continent - 接着计算每个大陆的总人口;
SUM(population) - 最后筛选出总人口≥1 亿的大陆,实现按组统计后的二次筛选。
HAVING
三、字符串拼接与类型转换
CONCAT
进阶函数
CONCAT() 用于将多个字符串(或字段值)合并成一个字符串,通常与数值函数(如 ROUND)和类型转换函数(如 CAST)结合使用,以处理“数值转字符串”、“添加单位符号”等场景。
示例:显示欧洲各国人口占德国人口的百分比(保留整数并添加百分号)
SELECT name,
CONCAT( -- 拼接整数和百分号
CAST( -- 将浮点型转换为整数
ROUND( -- 四舍五入保留0位小数
population * 100.0 / ( -- 计算占比(乘以100.0确保浮点运算)
SELECT population FROM world WHERE name = 'Germany' -- 子查询获取德国人口
), 0
) AS INT -- 转换为整数类型
),
'%' -- 百分号字符串
) AS population_percent
FROM world
WHERE continent = 'Europe';
分步解析:
- 子查询:
获取德国的人口数;SELECT population FROM world WHERE name = 'Germany' - 计算占比:
计算百分比数值(乘以population * 100.0 / 德国人口
避免整数除法);100.0 - 四舍五入:
将结果保留至0位小数(如ROUND(..., 0)
变为23.6
);24 - 类型转换:
将浮点数结果转换为整数(去除CAST(...) AS INT
后缀);.0 - 拼接符号:
将整数与百分号拼接(如CONCAT(..., '%')
变为24
)。24%
总结
本文详细介绍了 SQL 中子查询和聚合函数的主要用法:
- 子查询分为简单子查询(可独立执行)和相关子查询(依赖于主查询),分别适用于固定基准比较和动态分组筛选;
- 聚合函数(如
/COUNT
/SUM
/AVG
/MAX
)与MIN
结合使用,实现按组统计,而GROUP BY
用于筛选分组后的结果;HAVING
与数值函数和类型转换相结合,可以灵活地处理字符串拼接和格式化需求。CONCAT
掌握这些工具对于处理多条件统计、分组分析、复杂关联查询至关重要,能够显著提升使用 SQL 解决实际业务问题的能力。在实际应用中,需要注意子查询的性能优化(避免过度嵌套)和
GROUP BY 的语法规范,确保查询既高效又准确。

雷达卡


京公网安备 11010802022788号







