ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

MySQL必知必会——第十三章分组数据

2022-01-22 14:03:29  阅读:202  来源: 互联网

标签:GROUP 必知 MySQL HAVING 分组 第十三章 子句 WHERE id


分组数据

本章将介绍如何分组数据,以便能汇总表内容的子集。这涉及两个新SELECT语句子句,分别是GROUP BY和HAVING子句。

数据分组

上章(MySQL必知必会——第十二章汇总数据)我们使用SQL聚集函数来汇总数据。这使我们不用检索所有数据就能对行进行计数、计算和平均数等。

目前为止的计算都在表的所有数据或匹配特定的WHERE子句的数据上进行的。
例如,返回供应商1003提供的产品数目:

mysql> SELECT COUNT(*) AS num_prods
    -> FROM products
    -> WHERE vend_id = 1003;
+-----------+
| num_prods |
+-----------+
|         7 |
+-----------+
1 row in set (0.01 sec)

但如果我们想返回每个供应商提供的产品数目,或返回只提供单项产品的供应商提供的产品,或返回提供10个以上产品的供应商怎么办?。

明显这简单的聚集函数很难办到,我们可以使用分组。分组允许把数据分为多个逻辑组,以便能对每个组进行聚集计算。


创建分组

分组是在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 |
+---------+-----------+
4 rows in set (0.00 sec)

此SELECT语句指定了两个列,vend_id包含产品供应商的ID,num_prods为计算字段。GROUP BY子句指示MySQL按vend_id排序并分组数据。即,COUNT(*)对每个vend_id计算一次。

GROUP BY子句指示MySQL分组数据,然后对每个组而不是整个结果集进行聚集。

一些使用GROUP BY子句的重要规定:

  • GROUP BY子句可以包含任意数目的列。这能对分组进行嵌套,为数据分组提供更细致的控制。
  • 如果在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上进行汇总(不能从个别的列取回数据)。
  • GROUP BY子句中列出的每个列都必须是检索列或有效的表达式(但不能是聚集函数)。如果在SELECT中使用表达式,则必须在GROUP BY子句中年指定相同的表达式。不能使用别名。
  • 除聚集计算语句外,SELECT语句中的每个列都必须在GROUP BY子句中出现。
  • 如果分组列中具有NULL值,则NULL将作为一个分组返回。
  • GROUP BY子句必须出现在WHERE子句后,ORDER BY子句前。

使用ROLLUP 使用WITH ROLLUP关键字,可以得到每个分组以及每个分组汇总级别的值,例如

mysql> SELECT vend_id, COUNT(*) AS num_prods
    -> FROM products
    -> GROUP BY vend_id WITH ROLLUP;
+---------+-----------+
| vend_id | num_prods |
+---------+-----------+
|    1001 |         3 |
|    1002 |         2 |
|    1003 |         7 |
|    1005 |         2 |
|    NULL |        14 |
+---------+-----------+
5 rows in set (0.00 sec)

过滤分组

除了能用GROUP BY分组数据外,MySQL还允许过滤分组,规定包括哪些分组,排除哪些分组。

谈过滤,我们会想到WHERE子句(MySQL必知必会——第六章过滤数据)。但WHERE过滤指定的行,并非分组,所以我们需要另外的子句,HAVING子句。

HAVING非常类似于WHERE。目前所以WHERE子句都可以用HAVING代替,而唯一的区别是,WHERE过滤行,HAVING过滤分组。

  • HAVING支持所有WHERE操作符 我们所学过的有关WHERE的所有技术和选项都适用于HAVING。

过滤拥有两个及两个以上订单的分组:

mysql> SELECT cust_id, COUNT(*) AS orders
    -> FROM orders
    -> GROUP BY cust_id
    -> HAVING COUNT(*) >= 2;
+---------+--------+
| cust_id | orders |
+---------+--------+
|   10001 |      2 |
+---------+--------+
1 row in set (0.01 sec)
  • HAVING和WHERE的差别 WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。WHERE排除的行不包括在分组中,这可能改变计算值,从而影响HAVING子句中过滤的分组。

我们可以同时使用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 |
+---------+-----------+
2 rows in set (0.00 sec)

此语句中,WHERE子句过滤所有prod_price至少为10的行,然后按vend_id进行分组数据,再通过HAVING子句过滤计数至少为2的分组。

无WHERE的对比:

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 |
+---------+-----------+
4 rows in set (0.00 sec)

分组和排序

GROUP BY和ORDER BY经常完成相同的工作,但它们是非常不一样的。

ORDER BY与GROUP BY的差别:

ORDER BYGROUP BY
排序产生的结果分组行。但输出可能不是分组的顺序
任意列都可以使用(甚至非选择列)只能使用选择列或表达式列,且必须使用选择表达式
不一定需要与聚集函数一起使用列(或表达式),则有必要

我们经常发现GROUP BY分组的数据是以分组的顺序输出的,但并不总是这样。我们应该明确提供ORDER BY子句,来进行排序。

  • 不要忘记ORDER BY 一般在使用GROUP BY子句时,应该也给出ORDER BY子句。这是保证数据正确排序的唯一方法。

检索订单总价大于等于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 |
+-----------+------------+
4 rows in set (0.00 sec)

我们在按订单总价排序输出:

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 |
+-----------+------------+
4 rows in set (0.00 sec)

SELECT子句顺序

回顾当前SELECT语句中子句的顺序,列表顺序:

子句说明是否必须使用
SELECT要返回的列或表达式
FROM从中检索数据的表仅在从表中选择数据时使用
WHERE行级过滤
GROUP BY分组说明仅在分组计算聚集时使用
HAVING组级过滤
ORDER BY输出排序顺序
LIMIT要检索的行数

标签:GROUP,必知,MySQL,HAVING,分组,第十三章,子句,WHERE,id
来源: https://blog.csdn.net/Jerome_Tong/article/details/122636654

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有