3-2对表进行分组

SQL
Author

Rui

Published

November 11, 2022

3-2 对表进行分组

GROUP BY 子句

将表按某一列或某几列分成几组,再进行汇总

SELECT <列名1>, ...
  FROM <表名>
 GROUP BY <列名1>, ...;

按照商品种类统计数据行数:

SELECT product_type, COUNT(*)
  FROM Product
 GROUP BY product_type;
3 records
product_type count
衣服 2
办公用品 2
厨房用具 4

GROUP BY 子句中指定的列称为聚合键分组列,能够决定分组方式。

Note

SQL 中子句的顺序十分重要。到目前为止,所接触的子句的书写顺序为:

SELECT -> FROM -> WHERE -> GROUP BY

聚合键中包含 NULL

聚合键中包含 NULL 时,GROUP BY 会把所有 NULL 合并为一组。

比如进货单价 purchase_price 一列包含两条 NULL 值。以 purchase_price 为聚合键进行分组:

SELECT purchase_price, COUNT(*)
  FROM Product
 GROUP BY purchase_price
6 records
purchase_price count
NA 2
320 1
500 1
2800 2
5000 1
790 1

使用 WHERE 子句时 GROUP BY 的执行结果

SELECT <列名1>, ...
  FROM <表名>
 WHERE <条件表达式>
 GROUP BY <列名1>, ...;

先根据 WHERE 子句指定的条件进行过滤,然后再进行汇总处理。

Note

SQL 的执行顺序与书写顺序不一样。到目前位置所接触的子句的执行顺序为:

FROM -> WHERE -> GROUP BY -> SELECT

SELECT purchase_price, COUNT(*)
  FROM Product
 WHERE product_type = '衣服'
 GROUP BY purchase_price;
2 records
purchase_price count
500 1
2800 1

以上代码的执行顺序为:首先选定 Product 表,从表中选出商品类型为“衣服”的数据,再对数据依据进价进行分组,最后计算不同进价的商品的数量。

几种常见错误

1. 在 SELECT 子句中书写了多余的列

SELECT 子句中只能存在三种元素:常数聚合函数GROUP BY 中指定的列名(聚合键)。如果 SELECT 子句中出现了聚合键以外的列,结果就会报错。

错误的方法:

SELECT product_name, purchase_price, COUNT(*)
  FROM Product
 GROUP BY purchase_price;

之所以会报错,是因为在你所期望的输出结果中 purchase_price 和 COUNT(*) 是一一对应的,可以放在一行; 但是 product_name 和 purchase_price 不一定是一一对应的,若不对应就无法放在同一行中。

2. 在 GROUP BY 子句中使用列的别名

SELECT 子句中可以使用关键字 AS 来设置列的别名,但 GROUP BY 子句中不能使用别名。

Note

因为 GROUP BY 的执行顺序先于 SELECT,GROUP BY 无法找到之后 SELECT 指定的列名。

3. GROUP BY 子句的结果能排序吗

GROUP BY 返回的结果完全随机。若想排序,方法在第 4 章。

4. 在 WHERE 子句中使用聚合函数

错误的做法:

SELECT product_type, COUNT(*)
  FROM Product
 WHERE COUNT(*) = 2
 GROUP BY product_type;

造成错误的原因还是在于 SQL 子句的执行顺序。

Note

只有 SELECTHAVING 以及 ORDER BY 子句能够使用 COUNT 等聚合函数。

5. 到底使用哪个?

方法一:

SELECT DISTINCT product_type
  FROM Product;
3 records
product_type
衣服
办公用品
厨房用具

方法二:

SELECT product_type
  FROM Product
 GROUP BY product_type;
3 records
product_type
衣服
办公用品
厨房用具

DISTINCT 和 GROUP BY 都可以删除后续列的重复数据。上面两种方法的结果差不多,执行速度也差不多。到底哪种方法更好呢?

解答:

  • GROUP BY 一般会与聚合函数联用。不联用的话不会报错,但是只返回聚合键的结果,让人费解为什么要分组(是否有必要分组)。

  • “想要删除选择结果中的重复记录”时使用 DISTINCT,“想要计算分组结果”时使用 GROUP BY。

  • SQL 语句的语法与英语十分相似,所以理解起来较为容易。不应该浪费这一优势(比如以上的例子)。