10.3 过滤分组
除了能用GROUP BY
分组数据外,SQL还允许过滤分组,规定包括哪些分组,排除哪些分组。例如,你可能想要列出至少有两个订单的所有顾客。为此,必须基于完整的分组而不是个别的行进行过滤。
我们已经看到了WHERE
子句的作用(第4课提及)。但是,在这个例子中WHERE
不能完成任务,因为WHERE
过滤指定的是行而不是分组。事实上,WHERE
没有分组的概念。
那么,不使用WHERE
使用什么呢?SQL为此提供了另一个子句,就是HAVING
子句。HAVING
非常类似于WHERE
。事实上,目前为止所学过的所有类型的WHERE
子句都可以用HAVING
来替代。唯一的差别是,WHERE
过滤行,而HAVING
过滤分组。
提示:
HAVING
支持所有WHERE
操作符
在第4课和第5课中,我们学习了WHERE
子句的条件(包括通配符条件和带多个操作符的子句)。学过的这些有关WHERE
的所有技术和选项都适用于HAVING
。它们的句法是相同的,只是关键字有差别。
那么,怎么过滤分组呢?请看以下的例子:
输入▼
SELECT cust_id, COUNT(*) AS orders
FROM Orders
GROUP BY cust_id
HAVING COUNT(*) >= 2;
输出▼
cust_id orders
---------- -----------
1000000001 2
分析▼
这条SELECT
语句的前三行类似于上面的语句。最后一行增加了HAVING
子句,它过滤COUNT(*) >= 2
(两个以上订单)的那些分组。
可以看到,WHERE
子句在这里不起作用,因为过滤是基于分组聚集值,而不是特定行的值。
说明:
HAVING
和WHERE
的差别
这里有另一种理解方法,WHERE
在数据分组前进行过滤,HAVING
在数据分组后进行过滤。这是一个重要的区别,WHERE
排除的行不包括在分组中。这可能会改变计算值,从而影响HAVING
子句中基于这些值过滤掉的分组。
那么,有没有在一条语句中同时使用WHERE
和HAVING
子句的需要呢?事实上,确实有。假如想进一步过滤上面的语句,使它返回过去12个月内具有两个以上订单的顾客。为此,可增加一条WHERE
子句,过滤出过去12个月内下过的订单,然后再增加HAVING
子句过滤出具有两个以上订单的分组。
为了更好地理解,来看下面的例子,它列出具有两个以上产品且其价格大于等于4
的供应商:
输入▼
SELECT vend_id, COUNT(*) AS num_prods
FROM Products
WHERE prod_price >= 4
GROUP BY vend_id
HAVING COUNT(*) >= 2;
输出▼
vend_id num_prods
------- -----------
BRS01 3
FNG01 2
分析▼
这条语句中,第一行是使用了聚集函数的基本SELECT
语句,很像前面的例子。WHERE
子句过滤所有prod_price
至少为4
的行,然后按vend_id
分组数据,HAVING
子句过滤计数为2或2以上的分组。如果没有WHERE
子句,就会多检索出一行(供应商DLL01
,销售4
个产品,价格都在4
以下):
输入▼
SELECT vend_id, COUNT(*) AS num_prods
FROM Products
GROUP BY vend_id
HAVING COUNT(*) >= 2;
输出▼
vend_id num_prods
------- -----------
BRS01 3
DLL01 4
FNG01 2
说明:使用
HAVING
和WHERE
HAVING
与WHERE
非常类似,如果不指定GROUP BY
,则大多数DBMS会同等对待它们。不过,你自己要能区分这一点。使用HAVING
时应该结合GROUP BY
子句,而WHERE
子句用于标准的行级过滤。