本章将介绍如何分组数据,以便能汇总表内容的子集。
这涉及两个新 SELECT 语句子句,分别是:GROUP BY 子句和 HAVING 子句。
10.1 数据分组
目前为止的所有计算都是在表的所有数据或匹配特定的 WHERE 子句的数据上进行的,比如,返回供应商 DLL01 提供的产品数目。
但是,如果要返回每个供应商提供的产品数目怎么办?或者返回只提供单项产品的供应商所提供的产品,或返回提供10个以上产品的供应商怎么办?
这就是分组出手的时候了。
分组允许把数据分为多个逻辑组,以便能对每个组进行聚集计算。
10.2 创建分组
分组是在 SELECT 语句的 GROUP BY 子句中建立的。
例 1:
SELECT vend_id, COUNT(*) AS num_prods
FROM Products
GROUP BY vend_id;
在具体使用 GROUP BY 子句前,需要知道一些重要的规定:
- GROUP BY 子句可以包含任意数目的列。这使得能对分组进行嵌套,为数据分组提供更细致的控制
- 如果在 GROUP BY 子句中嵌套了分组,数组将在最后规定的分组上进行汇总
- GROUP BY 子句中列出的每个列都必须是检索列或有效的表达式(但不能是聚集函数)
- 如果在 SELECT 中使用表达式,则必须在 GROUP BY 子句中指定相同的表达式,不能使用别名
- 除聚集计算语句外,SELECT 语句中的每个列都必须在 GROUP BY 子句中给出
- 如果分组列中具有 NULL 值,则 NULL 值将作为一个分组返回。如果列中有多行 NULL 值,它们将分为一组
- GROUP BY 子句必须出现在 WHERE 子句之后,ORDER BY 子句之前
通过相对位置指定列:有的 SQL 实现允许根据 SELECT 列表中的位置指定 GROUP BY 的列。
例如,GROUP BY 2,1 表示按选择的第二个列分组,然后再按第一个列分组
10.3 过滤分组
除了能用 GROUP BY 分组数据外,SQL 还允许过滤分组,规定包括哪些分组,排除哪些分组。
例如,可能想要列出至少有两个订单的所有顾客(为得出这种数据,必须基于完整的分组而不是个别的行进行过滤)。
在这个例子中,因为 WHERE 过滤指定的是列而不是分组,因此 WHERE 不能完成任务。
SQL 为此目的提供了 HAVING 子句。
HAVING 非常类似于 WHERE(目前为止所学过的所有类型的 WHERE 子句都可以用 HAVING 来代替)
唯一的差别是 WHERE 过滤行,而 HAVING 过滤分组
HAVING 支持所有 WHERE 操作符:
在第 4 章和第 5 章中,我们学习了 WHERE 子句的条件(包括通配符条件和带多个操作符的子句)。
所学过的有关 WHERE 的所有这些技术和选项都适用于 HAVING。
它们的句法是相同的,只是关键字有差别。
那么,怎么过滤行呢?
例 1:
SELECT cust_id, COUNT(*) AS orders
FROM Orders
GROUP BY cust_id
HAVING COUNT(*) >= 2;
这里的 HAVING 子句,它过滤 COUNT(*) >= 2(两个以上的订单)的那些分组。
这里 WHERE 子句不起作用,因为过滤是基于分组聚集值而不是特定行值的。
HAVAING 和 WHERE 的差别:这里有另一种理解方法,WHERE 在数据分组前进行过滤,HAVING 在数据分组后进行过滤。
那么,有没有在一条语句中同时使用 WHERE 和 HAVING 子句的需要呢?
例 2,列出具有两个以上、价格为 4 以上的产品的供应商:
SELECT vend_id, COUNT(*) AS num_prods
FROM Products
WHERE prod_price >= 4
GROUP BY vend_id
HAVING COUNT(*) >= 2;
WHERE 子句过滤所有 prod_price 至少为 4 行。
然后按 vend_id 分组数据,HAVING 子句过滤技术为 2 或 2 以上的分组。
10.4 分组和排序
虽然 GROUP BY 和 ORDER BY 经常完成相同的工作,但它们是非常不同的。
不要忘记 ORDER BY:一般在使用 GROUP BY 子句时,应该也给出 ORDER BY 子句,这是保证数据正确排序的唯一方法。
为说明 GROUP BY 和 ORDER BY 的使用方法,看例 3:
SELECT order_num, COUNT(*) AS items
FROM OrderItems
GROUP BY order_num
HAVING COUNT(*) >= 3;
SELECT order_num, COUNT(*) AS items
FROM OrderItems
GROUP BY order_num
HAVING COUNT(*) >= 3
ORDER BY items, order_num;
10.5 SELECT 子句顺序
下表是在 SELECT 语句中使用时必须遵循的次序