GROUP BY
语句是SQL中用来对数据实现分组聚集操作的语句,它可以根据数据表中的一个或多个属性(列)的不同值把数据分成不同的组,以实现对数据的分组统计等操作。下面是我根据个人学习经验对该语句做出的分析。
要了解分组的概念,首先让我们来熟悉一下SQL中的基本聚集函数:
AVG()
MIN()
MAX()
SUM()
COUNT()
所有这些聚集函数,都是以一个集合作为输入,经过聚集作用后输出一个值的函数,换言之,假设 x1,x2......xn 是一个数据表内的各个元组,则聚集函数就是关于所有这些元组的函数:
我们使用聚集函数COUNT()来计算表中元组的总个数:
SELECT COUNT(*) FROM employees;
可以得到输出结果为:
+----------+
| COUNT(*) |
+----------+
| 4 |
+----------+
在这里,COUNT()
把表中的4个元组看成一组,然后把该组中各个元组作为自变量输入,统计它们的总个数后输出计数结果。
对于含有 WHERE
选择子句的查询语句,则先对表中的每个元组进行筛选,选出符合条件的元组合成一个组,再将该组中的各个元组作为自变量输入到 COUNT()
函数中计算结果。
统计employees表中女员工的数量:
SELECT COUNT(*)
FROM employees E
WHERE E.gender = 'F';
输出结果为:
+----------+
| COUNT(*) |
+----------+
| 2 |
+----------+
如上所述,聚集函数是把整个数据表中的所有元组看成一个组来进行聚集映射,但是在实际中,我们常常会根据数据的某一个或多个属性,把元组按其对应属性值的不同分成多个不同的组。假设根据属性 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 employees
GROUP BY gender;
输出结果为:
+--------------+
| AVG(salary) |
+--------------+
| 15000.000000 |
+--------------+
| 13825.000000 |
+--------------+
统计结果虽然出来了,但我们并不知道上面的结果分别是对应哪个分组的,因此把分组的属性显示出来:
SELECT gender, AVG(salary)
FROM employees
GROUP BY gender;
输出结果为:
+--------+--------------+
| gender | AVG(salary) |
+--------+--------------+
| M | 15000.000000 |
+--------+--------------+
| F | 13825.000000 |
+--------+--------------+
在这里需要特别注意一点,这个在《数据库系统概念 第六版》中也有强调:
当SQL查询使用分组时,一个很重要的事情是需要保证出现在 select 语句中但没有被聚集的属性只能是出现在 group by 子句中的那些属性。换句话说,任何没有出现在 group by 子句中的属性如果出现在 select 子句中的话,它只能出现在聚集函数内部,否则这样的查询就是错误的。
例如,如下的查询是错误的:
SELECT name, gender, AVG(salary)
FROM employees
GROUP 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
子句用于对分组后根据每个组的运算结果对组进行筛选,选出符合条件的分组进行显示。例如,对上面的employees表选出平均工资大于14000的分组:
SELECT gender, AVG(salary)
FROM employees
GROUP BY gender
HAVING AVG(salary) > 14000;
输出结果如下:
+--------+--------------+
| gender | AVG(salary) |
+--------+--------------+
| M | 15000.000000 |
+--------+--------------+
注意 HAVING
子句也与 SELECT
子句的限制条件一样,其后面的属性只能是出现在 GROUP BY
子句中的那些属性!如果不满足这个条件,mysql数据库管理系统也会报错:
SELECT gender, AVG(salary)
FROM employees
GROUP BY gender
HAVING name = 'Jackie Cheng';
报错如下:
Error Code: 1054. Unknown column 'name' in 'having clause' 0.016 sec
以上是我个人对SQL中的聚集函数、GROUP BY
语句和 HAVING
语句的学习总结,总结不到位或有错误之处欢迎大家指正。