目录
数据分组
创建分组
使用 GROUP BY 的规定:
ALL 子句
过滤分组
提示:HAVING 支持所有WHERE 操作符
HAVING 和WHERE 的差别
使用HAVING 和WHERE
分组和排序
不要忘记ORDER BY
SELECT 子句顺序
使用分组可以将数据分为多个逻辑组,对每个组进行聚集计算。
分组是使用SELECT 语句的GROUP BY 子句建立的。理解分组的最好办法是看一个例子:
SELECT vend_id, COUNT(*) AS num_prods FROM Products GROUP BY vend_id;
因为使用了GROUP BY,就不必指定要计算和估值的每个组了。系统会自动完成。GROUP BY 子句指示DBMS 分组数据,然后对每个组而不是整个结果集进行聚集。
Microsoft SQL Server 等有些SQL 实现在GROUP BY 中支持可选的ALL子句。这个子句可用来返回所有分组,即使是没有匹配行的分组也返回(在此情况下,聚集将返回NULL)。具体的DBMS 是否支持ALL,请参阅相应的文档。
我们已经看到了WHERE 子句的作用(第4 课提及)。但是,在这个例子中WHERE 不能完成任务,因为WHERE 过滤指定的是行而不是分组。事实上,WHERE 没有分组的概念。
那么,不使用WHERE 使用什么呢?SQL 为此提供了另一个子句,就是HAVING 子句。HAVING 非常类似于WHERE。事实上,目前为止所学过的所有类型的WHERE 子句都可以用HAVING 来替代。唯一的差别是,WHERE过滤行,而HAVING 过滤分组。
在第4 课和第5 课中,我们学习了WHERE 子句的条件(包括通配符条件和带多个操作符的子句)。学过的这些有关WHERE 的所有技术和选项都适用于HAVING。它们的句法是相同的,只是关键字有差别。
SELECT cust_id, COUNT(*) AS orders FROM Orders GROUP BY cust_id HAVING COUNT(*) >= 2;
在某些情形下,我们需要满足一定条件,同时又要结果个数>1的数据,或者或需要个数≥2的数据,这种情况下使用 having 就很合适。(HAVING COUNT(*) >= 2;)
这里有另一种理解方法,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;
这条语句中,第一行是使用了聚集函数的基本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;
HAVING 与WHERE 非常类似,如果不指定GROUP BY,则大多数DBMS会同等对待它们。不过,你自己要能区分这一点。使用HAVING 时应该结合GROUP BY 子句,而WHERE 子句用于标准的行级过滤。
GROUP BY 和ORDER BY 经常完成相同的工作,但它们非常不同,理解这一点很重要。下表汇总了它们之间的差别。
表中列出的第一项差别极为重要。我们经常发现,用GROUP BY 分组的数据确实是以分组顺序输出的。但并不总是这样,这不是SQL 规范所要求的。此外,即使特定的DBMS 总是按给出的GROUP BY 子句排序数据,用户也可能会要求以不同的顺序排序。就因为你以某种方式分组数据(获得特定的分组聚集值),并不表示你需要以相同的方式排序输出。应该提供明确的ORDER BY 子句,即使其效果等同于GROUP BY 子句。
简单来说就是,GROUP BY会对数据进行分组,但输出的结果不一定会按照升序/降序的方式输出,想要实现升序/降序,请配合使用 Order by子句。
一般在使用GROUP BY 子句时,应该也给出ORDER BY 子句。这是保证数据正确排序的唯一方法。千万不要仅依赖GROUP BY 排序数据。
为说明GROUP BY 和ORDER BY 的使用方法,来看一个例子。下面的SELECT语句类似于前面那些例子。它检索包含三个或更多物品的订单号和订购物品的数目:
SELECT order_num, COUNT(*) AS items
FROM OrderItems
GROUP BY order_num
HAVING COUNT(*) >= 3;
要按订购物品的数目排序输出,需要添加ORDER BY 子句,如下所示:
SELECT order_num, COUNT(*) AS items
FROM OrderItems
GROUP BY order_num
HAVING COUNT(*) >= 3
ORDER BY items, order_num;
order_num items
--------- -----
20009 3
20007 5
20008 5
在这个例子中,使用GROUP BY 子句按订单号(order_num 列)分组数据,以便COUNT(*)函数能够返回每个订单中的物品数目。HAVING 子句过滤数据,使得只返回包含三个或更多物品的订单。最后,用ORDER BY子句排序输出。
下面回顾一下SELECT 语句中子句的顺序。下表以在SELECT 语句中使用时必须遵循的次序,列出迄今为止所学过的子句。