聚集函数把整张表压成一行,GROUP BY 把表切成几堆、每堆各压一行。这一章讲清三件事:怎么切、
切完怎么筛(HAVING)、切完怎么排。
Demo 里 13 个产品按供应商切成 4/2/6/1 四堆;
HAVING 留下三堆,加上 WHERE 先筛行就只剩两堆;
把 COUNT(*) 写进 WHERE 会当场报错——那是 WHERE 执行时还不存在的东西。
上一章的聚集函数只能出一行,那是「整表一堆」的特例。 这一章把「一堆」变成「好几堆」,聚集函数才真正有用。 HAVING 与 WHERE 的分工是本章的分水岭:WHERE 在分组前砍行,HAVING 在分组后砍堆。 写反了要么报错、要么结果不对。
一、数据分组:把行分堆再各算一遍
上一章问「所有产品的平均价」,一句话就够。可业务上要的往往是「每家供应商的平均价」—— 这就得先把行按供应商分成堆。 不做分组只有两条路:每家发一条查询(几家就几次往返),或者把 13 行全取回来在应用里算。 GROUP BY 把这件事交给数据库。 分组之后,SELECT 里能出现的东西变少了:只能是分组列和聚集函数, 写别的一律报错或给出无意义的随机值——因为它不知道该取哪一行。
二、创建分组:GROUP BY
GROUP BY vend_id 的意思是「按 vend_id 的值把行分堆」,
然后再对每堆各跑一次 SELECT 里的聚集函数。
13 行切成 4 堆:1001 四个、1002 两个、1003 六个、1005 一个。
每堆出一行,所以结果 4 行。
GROUP BY 后面可以跟多列:GROUP BY order_num, prod_id 是「先按单号切,
再在每张单里按产品切」。切得越细,堆越多、每堆越小。
教材强调:GROUP BY 里的列必须是「检索列或表达式」,不能拿别名或聚集函数来分组。
而且 NULL 自己会成一堆,这点要注意。
三、过滤分组:HAVING 与 WHERE 的分工
HAVING 长得像 WHERE,位置也像,但它筛的是堆不是行。
所以 HAVING 里可以用聚集函数:HAVING COUNT(*) >= 2 是「只留至少两个产品的组」。
WHERE 在分组之前执行,HAVING 在分组之后执行。
这就是为什么 WHERE COUNT(*) >= 2 会报错——那时候还没数过,COUNT(*) 根本不存在。
两者可以同时用:WHERE prod_price >= 10 GROUP BY vend_id HAVING COUNT(*) >= 2。
先把便宜的行砍掉再分组,堆自然就小了,这比先分组再筛更省事。
一条实用原则:凡是能用 WHERE 的,别拖到 HAVING。
WHERE 少读一行,后面所有步骤都少算一次。
四、分组和排序
GROUP BY 不保证顺序。 结果看着像按组号升序,那只是当前实现的巧合,
换个版本、加个索引就可能变。
要顺序就自己写 ORDER BY,而且ORDER BY 可以按聚集结果排:
ORDER BY num_prods DESC 让产品最多的那组排最前。
别用 GROUP BY 代替 ORDER BY,也别指望它俩的顺序一致——教材专门点了这一条,
因为它在小数据上「看起来总是对的」。
五、SELECT 子句的顺序
书写顺序是固定的:SELECT、FROM、WHERE、GROUP BY、HAVING、ORDER BY、LIMIT。 写反就是语法错,不是风格问题。 执行顺序不一样:FROM 取表、WHERE 筛行、GROUP BY 分堆、HAVING 筛堆、SELECT 算列、ORDER BY 排、 LIMIT 截。 记住执行顺序有个直接好处:能解释「为什么别名在 WHERE 里用不了」。 因为 WHERE 执行时 SELECT 还没算,别名还不存在;ORDER BY 在 SELECT 之后,所以能用。
六、小结
教材小结:GROUP BY 分组、HAVING 筛组、ORDER BY 排序,SELECT 子句顺序不能乱。 本课补三条:一是 GROUP BY 不保证顺序;二是能用 WHERE 就别用 HAVING; 三是分组后 SELECT 只能用分组列和聚集函数。
七、动手 Demo:从一堆到四堆,再筛到两堆
Demo 六段:先分组数产品,再看顺序不可靠,然后加多列分组,接着用 HAVING 筛组、 WHERE 加 HAVING 一起用,最后故意把条件放错位置看报错。 每一段都能用行数自证:四组、三组、两组,数字对得上就说明写对了。
import sqlite3
con = sqlite3.connect(":memory:")
# 按供应商分组,各数一次
con.execute("SELECT vend_id, COUNT(*) AS num_prods FROM products GROUP BY vend_id")
# GROUP BY 不保证顺序,要顺序自己写 ORDER BY
con.execute("SELECT vend_id, COUNT(*) AS num_prods FROM products "
"GROUP BY vend_id ORDER BY num_prods DESC")
# 按多列分组:先按单号切,再在单里按产品切
con.execute("SELECT order_num, prod_id, quantity FROM orderitems "
"GROUP BY order_num, prod_id")
# HAVING 筛组,能用聚集函数
con.execute("SELECT vend_id, COUNT(*) AS num_prods FROM products "
"GROUP BY vend_id HAVING COUNT(*) >= 2")
# WHERE 先筛行,HAVING 后筛组
con.execute("SELECT vend_id, COUNT(*) AS num_prods FROM products "
"WHERE prod_price >= 10 GROUP BY vend_id HAVING COUNT(*) >= 2")
# 把 HAVING 的条件错写进 WHERE:这里会报 misuse of aggregate
try:
con.execute("SELECT vend_id, COUNT(*) AS n FROM products "
"WHERE COUNT(*) >= 2 GROUP BY vend_id")
except sqlite3.OperationalError as e:
print("报错:", e)
实跑输出:
--------------------------------------------------------------------
第十三课:分组数据
--------------------------------------------------------------------
【一】先看问题:每家供应商各有几个产品
SQL> SELECT vend_id, COUNT(*) AS num_prods FROM products GROUP BY vend_id
vend_id num_prods
----------------------
1001 4
1002 2
1003 6
1005 1
(4 行)
**四组,13 行被切成 4/2/6/1。** GROUP BY 的意思是「按这一列的值把行分堆,每堆各算一遍」。
**没有 GROUP BY 的时候整表一堆,只出一行;有了它,一堆一行。**
【二】GROUP BY 的默认顺序不可靠
SQL> SELECT vend_id,
COUNT(*) AS num_prods FROM products GROUP BY vend_id ORDER BY num_prods DESC
vend_id num_prods
----------------------
1003 6
1001 4
1002 2
1005 1
(4 行)
**结果看着是「按组号升序」,但那只是巧合。** 教材专门提醒:
**GROUP BY 不保证顺序,要顺序必须自己写 ORDER BY。**
上面那句按数量降序排,**1003 的六个跑到最前面了。**
【三】按多列分组:切得更细
SQL> SELECT order_num, COUNT(*) AS items FROM orderitems GROUP BY order_num
order_num items
------------------------
20005 4
20006 1
20007 1
20008 1
20009 4
(5 行)
**五张单:20005 与 20009 各四件,其余三张各一件。**
SQL> SELECT order_num, prod_id, quantity FROM orderitems GROUP BY order_num,
prod_id ORDER BY order_num LIMIT 8
order_num prod_id quantity
------------------------------------
20005 ANV01 10
20005 ANV02 3
20005 FB 1
20005 TNT2 5
20006 JP2000 1
20007 TNT2 100
20008 FC 50
20009 FB 1
(8 行)
**两列一起分组,等于先按单号切、再在每张单里按产品切。**
只有 (单号, 产品) 全相同的行才会落到同一堆。
【四】过滤分组:HAVING 与 WHERE 的分工
SQL> SELECT vend_id, COUNT(*) AS num_prods FROM products GROUP BY vend_id HAVING COUNT(*) >= 2
vend_id num_prods
----------------------
1001 4
1002 2
1003 6
(3 行)
**HAVING 是「分完组之后再筛」**,所以它能用聚集函数 `COUNT(*)`。 1005 只有 1 个产品,被筛掉了。
SQL> SELECT vend_id,
COUNT(*) AS num_prods FROM products WHERE prod_price >= 10 GROUP BY vend_id HAVING COUNT(*) >= 2
vend_id num_prods
----------------------
1001 2
1003 3
(2 行)
**WHERE 先筛行、HAVING 后筛组**:这句先只留价格不低于 10 的 6 行,再分组,再要求每组至少 2 个。
**一句话记住分工:WHERE 管行,HAVING 管组。** **凡是能用 WHERE 的,别拖到 HAVING**——
先在行层面砍掉,分组才省事。
【五】把条件挪错位置会怎样
**报错:misuse of aggregate: COUNT()**
**WHERE 执行的时候还没分组,COUNT(*) 根本不存在**,所以这里只能写 HAVING。
【六】SELECT 子句的书写顺序
顺序 子句 作用
----------------------------------------------------------------------
1 SELECT 要哪些列
2 FROM 从哪张表来
3 WHERE 先筛行
4 GROUP BY 把行分堆
5 HAVING 再筛堆
6 ORDER BY 最后排序
7 LIMIT 只取前几行
**这个顺序不能乱**:HAVING 写在 GROUP BY 前面是语法错,ORDER BY 写在 WHERE 前面也是。
**顺带说一句执行的顺序不完全一样**:
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT。
**SELECT 里的别名在 WHERE 里用不了,就是因为还没算到那一步。**
第一段分组。 四行结果对应四家供应商,4/2/6/1 加起来正好 13。
第二段排序。 1003 的六个排到最前,但别以为 GROUP BY 默认就这样排。
第三段多列分组。 五张单里 20005 与 20009 各四件,其余三张各一件。
第四段 HAVING。 要求至少两个产品,1005 那唯一的一个被筛掉,剩三组。
第五段 WHERE 加 HAVING。 先只留价格不低于 10 的 6 行,再分组,只剩 1001 与 1003 两组。
第六段故意写错。 把 COUNT(*) 放进 WHERE,引擎当场报 misuse of aggregate——它在提醒你:
这一步还没分组。
30 秒实验
- 把
HAVING COUNT(*) >= 2改成>= 4,还剩几组? - 用
GROUP BY vend_id加AVG(prod_price),看四组的平均价各是多少。 - 把
WHERE prod_price >= 10删掉,HAVING 那段的组数和每组数量会怎么变?
常见误区
- 把 HAVING 的条件写进 WHERE。WHERE 执行时还没分组,聚集函数不存在,直接报错。
- 以为 GROUP BY 会顺带排序。它不保证顺序,要顺序必须写 ORDER BY。
- 在 SELECT 里写没分组的列。分组后只能取分组列和聚集函数,否则取值无意义。
自测三问(点开对答案)
1. WHERE 和 HAVING 最根本的区别是什么? —— 执行时机不同:WHERE 在分组前筛行,HAVING 在分组后筛组;所以只有 HAVING 能用聚集函数。 2. 13 个产品按 vend_id 分成几组?各组几个? —— 四组:1001 四个、1002 两个、1003 六个、1005 一个,加起来 13。 3. 为什么 `SELECT` 里定义的别名不能在 `WHERE` 里用? —— 因为执行顺序是 WHERE 先于 SELECT,别名那时还没算出来;ORDER BY 在 SELECT 之后,所以能用。分组解决了「分类汇总」, 但一次只能查一层。 下一章学「查询套查询」——先把内层的结果算出来,再拿它当外层的条件。
- ☐ (本章完,下一章 第14章 使用子查询)