创建时间: 2026-09-01最后更新: 2026-09-01作者: yangbo(2d5d2525a)
1. 聚合函数
非聚合查询通常保留原始数据的行粒度,聚合查询则把一组输入行计算成一行统计结果。例如项目页面可能需要显示任务总数、已完成数量和最高优先级。没有 GROUP BY 时,全部输入行属于同一组;使用 GROUP BY 后,每个分组分别得到一行结果。
常用聚合函数包括:
| 函数 | 作用 |
|---|---|
COUNT(*) / COUNT(column) | 统计行数或非空值数量 |
SUM(column) | 对数值求和 |
AVG(column) | 计算数值的平均值 |
MIN(column) | 取非空值中的最小值 |
MAX(column) | 取非空值中的最大值 |
统计任务总数:
count-tasks.sql
1SELECT COUNT(*) AS task_count2FROM tasks;
不使用 GROUP BY 时,整个筛选结果被视为一组,因此只返回一行。即使表中没有数据,COUNT(*) 也会返回一行,结果为 0。
本文列出的带字段参数的聚合函数会忽略 NULL 输入,COUNT(*) 则直接统计行数。这使 COUNT(*) 与 COUNT(due_at) 的含义不同:
count-null.sql
1SELECT2COUNT(*) AS all_tasks,3COUNT(due_at) AS tasks_with_deadline4FROM tasks;
COUNT(*) 统计所有行,COUNT(due_at) 只统计截止时间不为 NULL 的行。命名结果列时应该让这种差异清楚可见。
2. 分组
GROUP BY 先按照字段把行分组,再对每一组执行聚合:
group-status.sql
1SELECT2status,3COUNT(*) AS task_count4FROM tasks5WHERE archived_at IS NULL6GROUP BY status7ORDER BY status;
如果未归档任务中有 todo、doing 和 done 三种状态,结果会为每种状态返回一行。当前练习数据只有未归档的 done 任务,因此实际执行只会得到一个分组。
SELECT 中没有参与聚合的列,通常必须出现在 GROUP BY 中:
group-project-status.sql
1SELECT2project_id,3status,4COUNT(*) AS task_count,5AVG(priority) AS average_priority6FROM tasks7GROUP BY project_id, status8ORDER BY project_id, status;
这里的 priority 是 smallint,但 PostgreSQL 执行 AVG(priority) 时会返回 numeric,所以平均值可能包含小数。展示时需要几位小数,应通过 round(AVG(priority), 2) 这类表达式或应用层格式化明确决定。
不能随意在这段查询中增加 title。同一个分组可能包含多条任务,数据库无法判断应该返回哪一个标题。聚合查询要求我们明确按什么维度分组以及对每组执行什么计算。
正在验证登录状态
请稍候,验证完成后将继续显示文章内容