想象一下,你在处理成千上万行数据——怎么在里面找到有用的信息?这时候 GROUP BY 操作符就像 SQL 里的指挥家一样登场了。它把杂乱无章的数据变成一首有节奏的旋律:统计、分组、总结。想知道每个客户下了多少订单、每门课有多少学生、或者各部门工资怎么分布?这些都靠 GROUP BY。今天我们就来聊聊怎么和它做朋友,把你的表用到极致。
分组其实就是把在某一列或几列里值相同的行合并成逻辑上的一组。这样你就能对每组单独用聚合函数了。
比如你有个员工表,想知道每个部门的平均工资。一个部门就是一组。SQL 用 GROUP BY 把员工表按部门分组,然后对每组用 AVG()。
GROUP BY 的语法
用 SQL 分组的核心规则:如果你用了 GROUP BY,那所有没用聚合函数的列都必须写在 GROUP BY 里。
语法:
SELECT 列1,
聚合函数(列2)
FROM 表
GROUP BY 列1;
操作步骤:
- 在
GROUP BY里写上你想分组的列。 - 用聚合函数来计算每组的值。
- 所有在
SELECT里但没用聚合函数的列,都得写在GROUP BY里。没写 SQL 会报错,别问为什么,SQL 就是这么严格。
例子:按院系分组学生
假设我们有个 students 表,存着学生的信息:
| id | name | faculty | gpa |
|---|---|---|---|
| 1 | Alex Lin | ComputerSci | 3.8 |
| 2 | Maria Chi | Math | 3.5 |
| 3 | Anna Song | ComputerSci | 4.0 |
| 4 | Otto Art | Math | 3.9 |
| 5 | Liam Park | Physics | 3.7 |
现在我们想知道每个院系的平均分(GPA)。写个带 GROUP BY 的查询:
SELECT faculty, AVG(gpa) AS avg_gpa
FROM students
GROUP BY faculty;
结果:
| faculty | avg_gpa |
|---|---|
| ComputerSci | 3.9 |
| Math | 3.7 |
| Physics | 3.7 |
SQL 先按 faculty 列把数据分组,然后对每组用 AVG()。
用 GROUP BY 的细节
SELECT里的列要求
SQL 要求你在 SELECT 里写的所有列,如果没用聚合函数(比如 SUM()、COUNT()),都得在 GROUP BY 里出现。因为没分组 SQL 不知道该显示哪个值。
试试下面这个查询,你会报错:
SELECT name, AVG(gpa)
FROM students
GROUP BY faculty;
错误:name 列没写在 GROUP BY 里。要修正,加上 name:
SELECT name, AVG(gpa)
FROM students
GROUP BY faculty, name;
但这样分组就到具体学生了——其实不是我们一开始想要的效果。
- 多列分组
你可以不只按一列分组,还能多列一起分组。比如除了院系还想按名字分组。直接在 GROUP BY 里加第二个列:
SELECT faculty, name, AVG(gpa) AS avg_gpa
FROM students
GROUP BY faculty, name;
原始表:
| id | name | faculty | gpa |
|---|---|---|---|
| 1 | Alex Lin | ComputerSci | 3.8 |
| 2 | Maria Chi | Math | 3.5 |
| 3 | Anna Song | ComputerSci | 4.0 |
| 4 | Otto Art | Math | 3.9 |
| 5 | Liam Park | Physics | 3.7 |
结果:
| faculty | name | avg_gpa |
|---|---|---|
| ComputerSci | Alex Lin | 3.8 |
| ComputerSci | Anna Song | 4.0 |
| Math | Maria Chi | 3.5 |
| Math | Otto Art | 3.9 |
| Physics | Liam Park | 3.7 |
- 用多个聚合函数分组
别只用一个聚合函数!比如我们想统计每个院系有多少学生,还想算平均分:
SELECT faculty,
COUNT(*) AS student_count,
AVG(gpa) AS avg_gpa
FROM students
GROUP BY faculty;
原始表:
| id | name | faculty | gpa |
|---|---|---|---|
| 1 | Alex Lin | ComputerSci | 3.8 |
| 2 | Maria Chi | Math | 3.5 |
| 3 | Anna Song | ComputerSci | 4.0 |
| 4 | Otto Art | Math | 3.9 |
| 5 | Liam Park | Physics | 3.7 |
结果:
| faculty | student_count | avg_gpa |
|---|---|---|
| ComputerSci | 2 | 3.9 |
| Math | 2 | 3.7 |
| Physics | 1 | 3.7 |
SQL 分组的细节:能选什么,不能选什么
写分组查询很简单,但你会发现一半的查询都跑不起来。分组的逻辑和我们脑子里想的不太一样。
如果你的 SQL 查询里有 GROUP BY,那结果里的所有列都要么是聚合函数算出来的,要么就是 GROUP BY 里分组用的列。
- 用聚合函数基于组内的列算出来的。
- 直接来自 GROUP BY——就是用来分组的列。
比如你对学生表做 GROUP BY 查询,结果表里是不会有具体学生的!你能有平均身高、平均体重、平均分。像下面这样写就不行:
SELECT faculty, name
FROM students
GROUP BY faculty;
我们来分析下为啥。
GROUP BY faculty 会把 students 表里的学生按 faculty 分组。每组学生的 faculty 都一样,所以可以说组有 faculty 这个属性。但 name 每个学生都不一样,所以组没有 name 这个属性。
GROUP BY faculty, gender 会把 students 表里的学生按 faculty 和 gender 分组。这样每组学生的 faculty 和 gender 都一样,所以组有这两个属性。但 name 还是没有。
这样写就没问题:
SELECT faculty, gender
FROM students
GROUP BY faculty, gender;
甚至可以这样:
SELECT
faculty,
gender,
AVG(age) as group_avg_age, -- 这个值是基于组内 age 算出来的
MAX(high) as group_high -- 这个值是基于组内 high 算出来的
FROM students
GROUP BY faculty, gender;
但直接在 SELECT 里用 age 和 high 是不行的。
用 GROUP BY 时常见的坑
你开始写 GROUP BY 查询时,这些坑很容易踩:
SELECT 里没写全列。 记住,所有不是聚合的列都得写在
GROUP BY里。不然 SQL 不知道怎么显示。按
NULL分组。NULL会被当成一个单独的组。如果你的列里有NULL,SQL 会给NULL单独分一组。分组太细。 如果你不小心在
GROUP BY里加了太多列,结果会特别细,分析起来很麻烦。
现在你已经知道怎么用 GROUP BY 高效分组数据了。这是 SQL 里最强大的工具之一,让你轻松搞定聚合数据和结构化报表。接下来我们还会继续深入分组的魔法,看看怎么用 HAVING 加更多过滤条件。
GO TO FULL VERSION