SQL GROUP BY 语句分析

来源:互联网 发布:网络交友新时空原文 编辑:程序博客网 时间:2024/06/05 13:38

GROUP BY 语句是SQL中用来对数据实现分组聚集操作的语句,它可以根据数据表中的一个或多个属性(列)的不同值把数据分成不同的组,以实现对数据的分组统计等操作。下面是我根据个人学习经验对该语句做出的分析。

聚集函数

要了解分组的概念,首先让我们来熟悉一下SQL中的基本聚集函数:

  • 求平均值: AVG()
  • 找最小值: MIN()
  • 找最大值: MAX()
  • 求和: SUM()
  • 计数: COUNT()

所有这些聚集函数,都是以一个集合作为输入,经过聚集作用后输出一个值的函数,换言之,假设 x1,x2......xn 是一个数据表内的各个元组,则聚集函数就是关于所有这些元组的函数:

Output=f(x1,x2......xn)
因此,对整个数据表使用聚集函数,相当于将表中的所有元组看成一个组,然后用相应的聚集函数作用于这个组中的所有元素,得到一个输出值。下面我们来看一个例子:
假设一个企业工资管理数据库中含有数据表employees如下:

这里写图片描述

我们使用聚集函数COUNT()来计算表中元组的总个数:

SELECT COUNT(*) FROM employees;

可以得到输出结果为:

+----------+| COUNT(*) |+----------+| 4        |+----------+

在这里,COUNT() 把表中的4个元组看成一组,然后把该组中各个元组作为自变量输入,统计它们的总个数后输出计数结果。

对于含有 WHERE 选择子句的查询语句,则先对表中的每个元组进行筛选,选出符合条件的元组合成一个组,再将该组中的各个元组作为自变量输入到 COUNT() 函数中计算结果。
统计employees表中女员工的数量:

SELECT COUNT(*)FROM employees EWHERE E.gender = 'F';

输出结果为:

+----------+| COUNT(*) |+----------+| 2        |+----------+

GROUP BY 分组聚集

如上所述,聚集函数是把整个数据表中的所有元组看成一个组来进行聚集映射,但是在实际中,我们常常会根据数据的某一个或多个属性,把元组按其对应属性值的不同分成多个不同的组。假设根据属性 Y 来对数据进行分组,Y 的值有 y1,y2,......ym,共m个不同的值,则对一张表的数据分组后有:
这里写图片描述
然后,对每一个分组都使用聚集函数并输出相应分组的计算结果,因此,对一张数据表中的m个分组运用聚集函数后将会得到m个输出 r1,r2......rm 输出的形式如下所示:

+----------+----------+| Y        | result   |+----------+----------+| y1       | r1       |+----------+----------+| y2       | r2       |+----------+----------+| ...      | ...      |+----------+----------+| ym       | rm       |+----------+----------+

我们再以上面的employees表为例子,这次我们为每个元组增加一个工资salary的属性:

这里写图片描述

然后我们用分组聚集函数,分别计算男员工和女员工的平均工资:

SELECT AVG(salary)FROM employeesGROUP BY gender;

输出结果为:

+--------------+| AVG(salary)  |+--------------+| 15000.000000 |+--------------+| 13825.000000 |+--------------+

统计结果虽然出来了,但我们并不知道上面的结果分别是对应哪个分组的,因此把分组的属性显示出来:

SELECT gender, AVG(salary)FROM employeesGROUP BY gender;

输出结果为:

+--------+--------------+| gender | AVG(salary)  |+--------+--------------+| M      | 15000.000000 |+--------+--------------+| F      | 13825.000000 |+--------+--------------+

在这里需要特别注意一点,这个在《数据库系统概念 第六版》中也有强调:

当SQL查询使用分组时,一个很重要的事情是需要保证出现在 select 语句中但没有被聚集的属性只能是出现在 group by 子句中的那些属性。换句话说,任何没有出现在 group by 子句中的属性如果出现在 select 子句中的话,它只能出现在聚集函数内部,否则这样的查询就是错误的。

例如,如下的查询是错误的:

SELECT name, gender, AVG(salary)FROM employeesGROUP BY gender;

这是因为,name既没有出现在 GROUP BY 中,也没有出现在聚集函数 AVG() 的内部。
然而在本人所使用的mysql 5.5.53数据库管理系统中,这种错误是允许的,mysql将会把每个分组的第一个元组的name显示出来,上述错误语句在mysql5.5.53中的执行结果为:

+---------------+---------+--------------+| name          | gender  | AVG(salary)  |+---------------+---------+--------------+| Jackie Cheng  | M       | 15000.000000 |+---------------+---------+--------------+| Anna May Wong | F       | 13825.000000 |+---------------+---------+--------------+

HAVING 子句

HAVING 子句用于对分组后根据每个组的运算结果对组进行筛选,选出符合条件的分组进行显示。例如,对上面的employees表选出平均工资大于14000的分组:

SELECT gender, AVG(salary)FROM employeesGROUP BY genderHAVING AVG(salary) > 14000;

输出结果如下:

+--------+--------------+| gender | AVG(salary)  |+--------+--------------+| M      | 15000.000000 |+--------+--------------+

注意 HAVING 子句也与 SELECT 子句的限制条件一样,其后面的属性只能是出现在 GROUP BY 子句中的那些属性!如果不满足这个条件,mysql数据库管理系统也会报错:

SELECT gender, AVG(salary)FROM employeesGROUP BY genderHAVING name = 'Jackie Cheng';

报错如下:

Error Code: 1054. Unknown column 'name' in 'having clause'  0.016 sec



以上是我个人对SQL中的聚集函数、GROUP BY 语句和 HAVING 语句的学习总结,总结不到位或有错误之处欢迎大家指正。

原创粉丝点击