创建时间: 2026-09-01最后更新: 2026-09-01

1. 聚合函数

非聚合查询通常保留原始数据的行粒度,聚合查询则把一组输入行计算成一行统计结果。例如项目页面可能需要显示任务总数、已完成数量和最高优先级。没有 GROUP BY 时,全部输入行属于同一组;使用 GROUP BY 后,每个分组分别得到一行结果。

常用聚合函数包括:

函数作用
COUNT(*) / COUNT(column)统计行数或非空值数量
SUM(column)对数值求和
AVG(column)计算数值的平均值
MIN(column)取非空值中的最小值
MAX(column)取非空值中的最大值

统计任务总数:

count-tasks.sql
1
SELECT COUNT(*) AS task_count
2
FROM tasks;

不使用 GROUP BY 时,整个筛选结果被视为一组,因此只返回一行。即使表中没有数据,COUNT(*) 也会返回一行,结果为 0。

本文列出的带字段参数的聚合函数会忽略 NULL 输入,COUNT(*) 则直接统计行数。这使 COUNT(*) 与 COUNT(due_at) 的含义不同:

count-null.sql
1
SELECT
2
COUNT(*) AS all_tasks,
3
COUNT(due_at) AS tasks_with_deadline
4
FROM tasks;

COUNT(*) 统计所有行,COUNT(due_at) 只统计截止时间不为 NULL 的行。命名结果列时应该让这种差异清楚可见。

2. 分组

GROUP BY 先按照字段把行分组,再对每一组执行聚合:

group-status.sql
1
SELECT
2
status,
3
COUNT(*) AS task_count
4
FROM tasks
5
WHERE archived_at IS NULL
6
GROUP BY status
7
ORDER BY status;

如果未归档任务中有 todo、doing 和 done 三种状态,结果会为每种状态返回一行。当前练习数据只有未归档的 done 任务,因此实际执行只会得到一个分组。

SELECT 中没有参与聚合的列,通常必须出现在 GROUP BY 中:

group-project-status.sql
1
SELECT
2
project_id,
3
status,
4
COUNT(*) AS task_count,
5
AVG(priority) AS average_priority
6
FROM tasks
7
GROUP BY project_id, status
8
ORDER BY project_id, status;

这里的 priority 是 smallint,但 PostgreSQL 执行 AVG(priority) 时会返回 numeric,所以平均值可能包含小数。展示时需要几位小数,应通过 round(AVG(priority), 2) 这类表达式或应用层格式化明确决定。

不能随意在这段查询中增加 title。同一个分组可能包含多条任务,数据库无法判断应该返回哪一个标题。聚合查询要求我们明确按什么维度分组以及对每组执行什么计算。

正在验证登录状态
请稍候,验证完成后将继续显示文章内容