13.1 创建分组
分组是在SELECT
语句的GROUP BY
子句中建立的。理解分组的最好办法是看一个例子:
mysql> SELECT vend_id, COUNT(*) AS num_prods FROM products GROUP BY vend_id;
+---------+-----------+
| vend_id | num_prods |
+---------+-----------+
| 1001 | 3 |
| 1002 | 2 |
| 1003 | 7 |
| 1005 | 2 |
+---------+-----------+
- 分析:上面的
SELECT
语句指定了两个列,vend_id
包含产品供应商的ID,num_prods
为计算字段(用COUNT(*)
函数建立)。GROUP BY
子句指示MySQL按vend_id
排序并分组数据。这导致对每个vend_id
而不是整个表计算num_prods
一次。从输出中可以看到,供应商1001有3个产品,供应商1002有2个产品,供应商1003有7个产品,而供应商1005有2个产品。
因为使用了GROUP BY
,就不必指定要计算和估值的每个组了。系统会自动完成。 GROUP BY
子句指示MySQL分组数据,然后对每个组而不是整个结果集进行聚集。
13.2 过滤分组
mysql> SELECT cust_id, COUNT(*) AS orders FROM orders GROUP BY cust_id HAVING COUNT(*) >= 2;
+---------+--------+
| cust_id | orders |
+---------+--------+
| 10001 | 2 |
+---------+--------+
- 分析:这条
SELECT
语句的前3行类似于上面的语句。最后一行增加了HAVING
子句,它过滤COUNT(*) >=2
(两个以上的订单)的那些分组。
HAVING和WHERE的差别:这里有另一种理解方法,WHERE在数据分组前进行过滤, HAVING在数据分组后进行过滤。
列出具有2个(含)以上、价格为10(含)以上的产品的供应商:
mysql> SELECT vend_id, COUNT(*) AS num_prods FROM products WHERE prod_price >= 10 GROUP BY vend_id HAVING COUNT(*) >= 2;
+---------+-----------+
| vend_id | num_prods |
+---------+-----------+
| 1003 | 4 |
| 1005 | 2 |
+---------+-----------+
- 分析:这条语句中,第一行是使用了聚集函数的基本
SELECT
,它与前面的例子很相像。WHERE
子句过滤所有prod_price
至少为10的行。然后按vend_id
分组数据,HAVING
子句过滤计数为2或2以上的分组。如果没有WHERE
子句,将会多检索出两行(供应商1002,销售的所有产品价格都在10以下;供应商1001,销售3个产品,但只有一个产品的价格大于等于10):
mysql> SELECT vend_id, COUNT(*) AS num_prods FROM products GROUP BY vend_id HAVING COUNT(*) >= 2;
+---------+-----------+
| vend_id | num_prods |
+---------+-----------+
| 1001 | 3 |
| 1002 | 2 |
| 1003 | 7 |
| 1005 | 2 |
+---------+-----------+
13.3 分组和排序
不要忘记ORDER BY:一般在使用GROUP BY
子句时,应该也给出ORDER BY
子句。这是保证数据正确排序的唯一方法。千万不要仅依赖GROUP BY
排序数据
为说明GROUP BY
和ORDER BY
的使用方法,请看一个例子。下面SELECT
语句类似于前面那些例子。它检索总计订单价格大于等于50的订单的订单号和总计订单价格:
mysql> SELECT order_num, SUM(quantity*item_price) AS ordertotal FROM orderitems GROUP BY order_num HAVING SUM(quantity*item_price) >= 50;
+-----------+------------+
| order_num | ordertotal |
+-----------+------------+
| 20005 | 149.87 |
| 20006 | 55.00 |
| 20007 | 1000.00 |
| 20008 | 125.00 |
+-----------+------------+
为按总计订单价格排序输出,需要添加ORDER BY子句,如下所示:
mysql> SELECT order_num, SUM(quantity*item_price) AS ordertotal FROM orderitems GROUP BY order_num HAVING SUM(quantity*item_price) >= 50 ORDER BY ordertotal;
+-----------+------------+
| order_num | ordertotal |
+-----------+------------+
| 20006 | 55.00 |
| 20008 | 125.00 |
| 20005 | 149.87 |
| 20007 | 1000.00 |
+-----------+------------+
- 分析:在这个例子中,
GROUP BY
子句用来按订单号(order_num列)分组数据,以便SUM(*)
函数能够返回总计订单价格。HAVING
子句过滤数据,使得只返回总计订单价格大于等于50的订单。最后, 用ORDER BY
子句排序输出。
13.4 SELECT子句顺序
在SELECT语句中使用时必须遵循的次序,列出迄今为止所学过的子句。
子 句 | 说 明 | 是否必须使用 |
---|---|---|
SELECT | 要返回的列或表达式 | 是 |
FROM | 从中检索数据的表 | 仅在从表选择数据时使用 |
WHERE | 行级过滤 | 否 |
GROUP BY | 分组说明 | 仅在按组计算聚集时使用 |
HAVING | 组级过滤 | 否 |
ORDER BY | 输出排序顺序 | 否 |
LIMIT | 要检索的行数 | 否 |