聚合函数
到现在为止,查询查出来的都是一行一行的记录。可很多问题要的是一个数:一共有几件商品?库存加起来有多少?最贵的多少钱?这种「把很多行算成一个数」的函数叫聚合函数。
1SELECT COUNT(*) FROM products;| COUNT(*) |
|---|
| 10 |
商品表有 10 行,结果只有一行一列:10。
数一数:COUNT
COUNT(*) 数的是行数。COUNT(列) 数的是这一列里不是 NULL 的格子有几个。客户表有 10 个客户,可有 3 个没留邮箱:
1SELECT COUNT(*), COUNT(email) FROM customers;| COUNT(*) | COUNT(email) |
|---|---|
| 10 | 7 |
同一张表,两个数不一样:COUNT(*) 是 10,COUNT(email) 是 7。想知道「有多少行」,用 COUNT(*);想知道「这一列填了多少」,用 COUNT(列)。
COUNT(DISTINCT 列) 只数不同的值。订单表里 12 个订单,下单的客户有几位?
1SELECT COUNT(*), COUNT(DISTINCT customer_id) FROM orders;| COUNT(*) | COUNT(DISTINCT customer_id) |
|---|---|
| 12 | 7 |
12 个订单,来自 7 位客户:有的客户下了不止一单。
加起来和平均:SUM、AVG
SUM 把一列加起来,AVG 算平均值:
1SELECT SUM(stock), AVG(price) FROM products;| SUM(stock) | AVG(price) |
|---|---|
| 585 | 19.080000 |
所有商品的库存一共 585 件,平均价格 19.08。MySQL 把平均值显示成 19.080000,多了几个 0。用第 6 课的 ROUND 和 AS 整理一下:
1SELECT SUM(stock) AS total_stock,2 ROUND(AVG(price), 2) AS avg_price3FROM products;
| total_stock | avg_price |
|---|---|
| 585 | 19.08 |
括号里也可以是一个算式。订单明细表里每一行是「几件 × 单价」,全部加起来就是网店一共卖了多少钱:
1SELECT SUM(quantity * unit_price) AS sales FROM order_items;| sales |
|---|
| 433.70 |
最大和最小:MAX、MIN
MAX 和 MIN 找最大和最小的值。数字、日期、文字都可以:
1SELECT MIN(price), MAX(price) FROM products;2SELECT MIN(order_date), MAX(order_date) FROM orders;
| MIN(price) | MAX(price) |
|---|---|
| 4.50 | 59.00 |
| MIN(order_date) | MAX(order_date) |
|---|---|
| 2025-09-02 | 2025-10-25 |
最便宜的商品 4.50,最贵的 59.00;第一个订单在 2025-09-02,最后一个在 2025-10-25。日期越早越「小」。
小技巧: 聚合函数都不管 NULL:SUM、AVG、MIN、MAX 遇到 NULL 的格子直接跳过,就像 COUNT(列) 不数它一样。
先 WHERE,再聚合
加上 WHERE,就只算留下来的那些行。数码类有几件商品,库存一共多少?
1SELECT COUNT(*), SUM(stock)2FROM products3WHERE category = '数码';
| COUNT(*) | SUM(stock) |
|---|---|
| 4 | 245 |
点单步看看:WHERE 先一行一行决定留不留,只剩 4 件数码商品;然后这 4 行才被算成一行。
要是一行都没留下呢?
1SELECT COUNT(*), SUM(stock)2FROM products3WHERE price > 100;
| COUNT(*) | SUM(stock) |
|---|---|
| 0 | NULL |
没有商品超过 100 块。COUNT(*) 是 0,SUM 却是 NULL:没有可以加的数,就没有和。
上海有 3 个客户,其中陈静没留邮箱。结果是多少?
1SELECT COUNT(email)2FROM customers3WHERE city = '上海';
WHERE 先留下上海的 3 个客户,COUNT(email) 再数邮箱不是 NULL 的,陈静那一格是 NULL,不算,所以是 2。要数人数,用 COUNT(*)。
很多行变成一行
聚合函数把很多行变成一行。所以它不能和普通的列放在一起:
1SELECT name, MAX(price) FROM products;ERROR 1140 (42000): In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'town.products.name'; this is incompatible with sql_mode=only_full_group_by
用了 COUNT / SUM 这类聚合函数又没写 GROUP BY 时,不能再单独选「name」这种普通的列:要么加 GROUP BY name,要么把它也放进聚合函数里。
MAX(price) 只有一个值,name 却有 10 个,该显示哪一个?MySQL 不替你猜,给出 ERROR 1140。想知道最贵的是哪件商品,第 4 课的写法就行:ORDER BY price DESC LIMIT 1。下一课的 GROUP BY 会让聚合不只算出一行,而是每组一行。
练一练
写好查询,点检查。提示随便看,实在想不出来再看答案。
价格一览
✓查出商品的最低价、最高价和平均价,列名分别叫 lowest、highest、average,平均价保留两位小数。
| lowest | highest | average |
|---|---|---|
| 4.50 | 59.00 | 19.08 |
1SELECT price FROM products;3 号订单
✓从 order_items 里算出 3 号订单一共买了几件(列名 items)、一共多少钱(列名 total)。
| items | total |
|---|---|
| 3 | 76.00 |
1SELECT * FROM order_items;修好它:数人数
✓这条查询想数北京有几个客户,结果却是 1,可北京明明有 2 个客户。改好它(列名就用 COUNT(*))。
| COUNT(*) |
|---|
| 2 |
1SELECT COUNT(email) FROM customers WHERE city = '北京';这一课学会了
- 聚合函数把很多行算成一个值:
COUNT、SUM、AVG、MIN、MAX。 COUNT(*)数行数;COUNT(列)不数 NULL;COUNT(DISTINCT 列)只数不同的值。SUM、AVG、MIN、MAX跳过 NULL;一行都没有时COUNT(*)是 0,SUM是 NULL。- 括号里可以写算式,比如
SUM(quantity * unit_price)。 WHERE先挑行,聚合函数再算剩下的。- 不分组时,聚合函数不能和普通的列放在一起(
ERROR 1140)。