SQL单表查询中的排序、聚合和分组是数据处理的核心操作。下面我将逐一详细解释,并给出清晰的操作指南和示例。
一、 排序操作 (ORDER BY)
用于对查询结果按照一个或多个列进行升序或降序排列。
基本语法:
SELECT 列1, 列2, ...
FROM 表名
[WHERE 条件]
ORDER BY 排序列1 [ASC | DESC], 排序列2 [ASC | DESC], ...;
ASC: 升序(默认,可不写)。
DESC: 降序。
- 可以按多列排序,先按第一列排,第一列值相同再按第二列排,以此类推。
示例:
假设有一张员工表 employees:
| emp_id |
name |
salary |
department |
hire_date |
|---|
| 1 |
张三 |
8000 |
技术部 |
2020-01-15 |
| 2 |
李四 |
9500 |
销售部 |
2019-03-22 |
| 3 |
王五 |
8000 |
技术部 |
2021-08-10 |
按工资降序排序
SELECT name, salary, department
FROM employees
ORDER BY salary DESC;
结果:
| name | salary | department |
|------|--------|------------|
| 李四 | 9500 | 销售部 |
| 张三 | 8000 | 技术部 |
| 王五 | 8000 | 技术部 |
按部门升序,再按工资降序排序
SELECT name, salary, department
FROM employees
ORDER BY department ASC, salary DESC;
结果:
| name | salary | department |
|------|--------|------------|
| 李四 | 9500 | 销售部 |
| 张三 | 8000 | 技术部 |
| 王五 | 8000 | 技术部 |
(注意:技术部内部,两个工资相同的人顺序可能不稳定,可再加 emp_id 作为第三排序条件保证确定性)
二、 聚合函数
用于对一组值进行计算并返回单个汇总值。常与分组 (GROUP BY) 结合使用,也可单独使用。
常用聚合函数:
| 函数 |
说明 |
是否忽略 NULL |
|---|
COUNT() |
统计行数。COUNT(*) 计数所有行;COUNT(列名) 统计该列非 NULL 值的行数。 |
视情况而定 |
SUM() |
计算数值列的总和。 |
是 |
AVG() |
计算数值列的平均值。 |
是 |
MAX() |
返回列中的最大值(适用于数值、日期、字符串)。 |
是 |
MIN() |
返回列中的最小值(适用于数值、日期、字符串)。 |
是 |
示例(单独使用):
统计员工总数SELECT COUNT(*) AS total_employees FROM employees;
计算公司总工资支出SELECT SUM(salary) AS total_salary FROM employees;
计算平均工资SELECT AVG(salary) AS avg_salary FROM employees;
三、 分组操作 (GROUP BY)
将查询结果按照一个或多个列进行分组,通常与聚合函数一起使用,以便对每个组进行汇总计算。
基本语法:
SELECT 分组列, 聚合函数(列), ...
FROM 表名
[WHERE 条件] -- 在分组前对原始数据进行筛选
GROUP BY 分组列1, 分组列2, ...
[HAVING 分组后条件]; -- 在分组后对聚合结果进行筛选
关键点:
SELECT 子句中出现的列,要么是 GROUP BY 子句中的列,要么是聚合函数计算的结果列。
WHERE 和 HAVING 的区别:WHERE:在分组前过滤行,不能使用聚合函数。
HAVING:在分组后过滤组,可以使用聚合函数。
示例:
统计每个部门的人数
SELECT department, COUNT(*) AS emp_count
FROM employees
GROUP BY department;
结果:
| department | emp_count |
|------------|-----------|
| 技术部 | 2 |
| 销售部 | 1 |
计算每个部门的平均工资
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department;
查找平均工资高于 8500 的部门
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 8500;
结果:
| department | avg_salary |
|------------|------------|
| 销售部 | 9500 |
统计每个部门2020年以后入职的员工数量
SELECT department, COUNT(*) AS emp_count
FROM employees
WHERE hire_date >= '2020-01-01' -- 分组前先筛选入职时间
GROUP BY department;
四、 完整查询执行顺序
理解SQL关键字的执行顺序非常重要,它决定了你能在哪个子句中使用哪些内容:
FROM: 确定数据来源表。
WHERE: 根据条件过滤
原始行。
GROUP BY: 对筛选后的数据进行分组。
HAVING: 对
分组后的聚合结果进行过滤。
SELECT: 选择要显示的列或计算表达式(包括聚合函数)。
ORDER BY: 对最终结果进行排序。
LIMIT / OFFSET (如有): 限制返回的行数。
因此,像 WHERE salary > AVG(salary) 这样的写法是错误的,因为 WHERE 执行时,AVG() 的组还没计算出来。正确的做法是使用子查询或窗口函数。
五、 综合示例
目标: 找出员工人数超过1人,且部门总工资超过15000的部门,并列出这些部门的总工资和平均工资,按平均工资降序排列。
SELECT
department,
COUNT(*) AS emp_count, -- 聚合函数:部门人数
SUM(salary) AS total_salary, -- 聚合函数:部门总工资
AVG(salary) AS avg_salary -- 聚合函数:部门平均工资
FROM employees
GROUP BY department -- 按部门分组
HAVING COUNT(*) > 1 -- 分组后条件:人数>1
AND SUM(salary) > 15000 -- 分组后条件:总工资>15000
ORDER BY avg_salary DESC; -- 按计算出的平均工资降序排序
通过组合排序(ORDER BY)、聚合函数(COUNT, SUM, AVG)和分组(GROUP BY),你可以从单张表中提取出大量有价值的信息。熟练掌握这些操作是进行复杂数据分析的基础。