🗄️ 第三章 操作数据库-SQL的使用方法
📄 一句话概括

GROUP BY 把记录按列值分堆、每堆各自聚合——【每个班的平均分】一句出结果,替掉 3-15 里那种一列查三遍的笨办法。

📝 本节和前面几节的关系

前四节的聚合都是【全班算一个数】;本节升级成【每组分一个数】——3-15 埋的伏笔在此回收。GROUP BY + 聚合函数是 1-7【分析场景】的真身,也是 SQL 的精华所在。

一、没有 GROUP BY 的笨办法

【每个班各多少人?】——3-15 的笨办法是查三遍:

SELECT COUNT(*) FROM students WHERE class = 1;   -- 2
SELECT COUNT(*) FROM students WHERE class = 2;   -- 2
SELECT COUNT(*) FROM students WHERE class = 3;   -- 1

班级数一多(一百个班)就成灾难。GROUP BY 一次到位:

二、GROUP BY 的写法与画面

-- 准备块(没建表先跑 3-6 的准备块)

SELECT class, COUNT(*)
FROM students
GROUP BY class;

输出:

class  COUNT(*)
1      2
2      2
3      1

执行画面分两步:

  1. 分堆:按 class 的值把 5 行分成三堆——{张三,李四}、{王五,赵六}、{钱七}
  2. 每堆聚合:每堆各跑一次 COUNT,压成一行
堆 1:张三 李四 → COUNT=2 → (1, 2)
堆 2:王五 赵六 → COUNT=2 → (2, 2)
堆 3:钱七     → COUNT=1 → (3, 1)

三、GROUP BY 的搭配规矩

SELECT 里只能出现两类东西:

  1. 分组的依据列(class)——每堆它只有一个值,报出来无歧义
  2. 聚合函数(COUNT/MAX/AVG…)——每堆压成一个数
-- 每班平均分(AVG 自动忽略钱七的 NULL,3-17 的口径延续)
SELECT class, AVG(score) AS 班平均 FROM students GROUP BY class;
class  班平均
1      88.5
2      71.0
3      <空>    ← 3 班只有钱七一人且 NULL,整堆无值可平均

错误示范:SELECT name, class, COUNT(*) ... GROUP BY class;——name 不在分组依据里,一堆里好几个名字,报哪个?DBMS 直接报错(或给不可靠结果)。

四、动手 Demo:分组三连

-- ① 每班人数
SELECT class, COUNT(*) AS 人数 FROM students GROUP BY class;

-- ② 每班平均分
SELECT class, AVG(score) AS 平均 FROM students GROUP BY class;

-- ③ 分组+排序:人数多的班在前
SELECT class, COUNT(*) AS 人数 FROM students GROUP BY class ORDER BY 人数 DESC;

看到什么算成功:①三行 2/2/1;②三班平均 88.5/71.0/空;③ GROUP BY 和 ORDER BY 同时上——先分堆聚合、再排顺序。

五、30 秒实验

1-7 的【本月卖得最好的前 10 名商品】现在能写了:

-- 伪表演示:把 students 想成销售表、class 想成商品、COUNT 想成销量
SELECT class AS 商品, COUNT(*) AS 销量
FROM students
GROUP BY class
ORDER BY 销量 DESC
LIMIT 10;

——分组、聚合、排序、限量四个零件一句串完,1-7 的分析场景正式落地。

六、常见误区

  1. "GROUP BY 是排序" —— 不是!它是分堆;要排序请另写 ORDER BY(有的 DBMS 会顺手排,别依赖)。
  2. "SELECT 里想放什么列就放" —— 只能放【分组依据列+聚合函数】;放别的列报错或不可靠。
  3. "WHERE 和 GROUP BY 顺序随便" —— 固定顺序 WHERE(先筛行)→ GROUP BY(再分堆)→ ORDER BY;分堆前先把不要的行筛掉,效率与语义都正确。
自测三问(点开对答案) 1. GROUP BY 干什么?执行画面两步? **分堆+每堆聚合;先按列值分堆,每堆各跑一次聚合压成一行**。 2. SELECT 里跟 GROUP BY 搭配只能放哪两类? **分组依据列+聚合函数**。 3. 【每班平均分】怎么写? **`SELECT class, AVG(score) FROM students GROUP BY class;`**。

相关笔记