SQL 入门教程:过滤(HAVING)分组(GROUP BY)

本文内容

目录汇总:SQL 零基础入门教程

除了能用 GROUP BY 分组数据外,SQL 还允许过滤分组,规定包括哪些分组,排除哪些分组。例如,你可能想要列出至少有两个订单的所有顾客。为此,必须基于完整的分组而不是个别的行进行过滤。

我们已经看到了 WHERE 子句 的作用。但是,在这个例子中 WHERE 不能完成任务,因为 WHERE 过滤指定的是行而不是分组。事实上,WHERE 没有分组的概念。

那么,不使用 WHERE 使用什么呢?SQL 为此提供了另一个子句,就是 HAVING 子句。HAVING 非常类似于 WHERE。事实上,目前为止所学过的所有类型的 WHERE 子句都可以用 HAVING 来替代。唯一的差别是,WHERE 过滤行,而 HAVING 过滤分组。

提示:HAVING 支持所有 WHERE 操作符

使用 WHERE 子句组合 WHERE 子句 中,我们学习了 WHERE 子句的条件(包括通配符条件和带多个操作符的子句)。学过的这些有关 WHERE 的所有技术和选项都适用于 HAVING。它们的句法是相同的,只是关键字有差别。

那么,怎么过滤分组呢?请看以下的例子:

输入▼

1
2
3
4
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 子句在这里不起作用,因为过滤是基于分组聚集值,而不是特定行的值。

说明:HAVINGWHERE 的差别

这里有另一种理解方法,WHERE 在数据分组前进行过滤,HAVING 在数据分组后进行过滤。这是一个重要的区别,WHERE 排除的行不包括在分组中。这可能会改变计算值,从而影响 HAVING 子句中基于这些值过滤掉的分组。

那么,有没有在一条语句中同时使用 WHEREHAVING 子句的需要呢?事实上,确实有。假如想进一步过滤上面的语句,使它返回过去 12 个月内具有两个以上订单的顾客。为此,可增加一条 WHERE 子句,过滤出过去 12 个月内下过的订单,然后再增加 HAVING 子句过滤出具有两个以上订单的分组。

为了更好地理解,来看下面的例子,它列出具有两个以上产品且其价格大于等于 4 的供应商:

输入▼

1
2
3
4
5
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 以下):

输入▼

1
2
3
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

说明:使用 HAVINGWHERE

HAVINGWHERE 非常类似,如果不指定 GROUP BY,则大多数 DBMS 会同等对待它们。不过,你自己要能区分这一点。使用 HAVING 时应该结合 GROUP BY 子句,而 WHERE 子句用于标准的行级过滤。

请参阅

(完)

comments powered by Disqus

本文内容