五种主流数据库:分组统计

五种主流数据库:分组统计本文详细介绍了如何在数据库中使用 GROUPBY 和 HAVING 进行数据分组和汇总 比较了 MySQL Oracle SQLServer PostgreSQL 和 SQLite 五种主流数据库的实现 并讨论了分组后的过滤策略

如果将数据按照某种规则进行分组,然后分别进行汇总,通常能够得到更详细的分析结果。例如,按照不同性别计算员工的平均月薪,按照不同的产品和渠道统计销售金额等。为了实现这种分组统计的效果,我们可以将聚合函数与分组操作(GROUP BY)结合使用。

本文比较五种主流数据库实现的分组统计功能,包括 MySQL、Oracle、SQL Server、PostgreSQL 以及 SQLite。

功能 MySQL Oracle SQL Server PostgreSQL SQLite
GROUP BY ✔️ ✔️ ✔️ ✔️ ✔️
HAVING ✔️ ✔️ ✔️ ✔️ ✔️

创建数据分组

GROUP BY 子句可以将数据按照某种规则进行分组。例如,以下查询使将员工按照性别进行分组:

SELECT sex AS "性别" FROM employee GROUP BY sex; 

其中,GROUP BY 表示将性别的每个不同取值分为一组,每个组返回一条记录。查询返回的结果如下:

性别 --- 男 女 

员工表中只存在 2 种不同的性别,因此返回了 2 条记录。我们也可以通过 DISTINCT 运算符实现相同的结果:

SELECT DISTINCT sex AS "性别" FROM employee; 

其中,DISTINCT 表示返回不重复的数据,查询结果和上面的示例相同。

我们也可以基于多个字段或表达式进行分组,从而创建更详细的分组。例如,以下语句按照不同的部门和性别进行分组:

SELECT dept_id AS "部门编号", sex AS "性别" FROM employee GROUP BY dept_id, sex; 

查询返回的结果如下:

部门编号|性别 ------|--- 1|2|3|4|4|5|

研发部(部门编号为 4)既有男性员工,又有女性员工,因此分为 2 个组。

进行组内汇总

我们可以结合使用 GROUP BY 子句与聚合函数,将数据进行分组,并在每个组内进行一次数据汇总。例如,以下语句按照不同的性别统计员工数量和平均月薪:

SELECT sex AS "性别", COUNT(*) AS "员工数量", AVG(salary) AS "平均月薪" FROM employee GROUP BY sex; 

其中 GROUP BY 用于将员工按照性别分为男、女两个组,然后利用 COUNT 和 AVG 函数分别计算男性员工和女性员工的总数和平均月薪。查询返回的结果如下:

性别|员工数量|平均月薪 ---|-------|------------| 22|10054.| 3| 8200.000000 

男性员工有 22 人,平均月薪约为 10055 ;女性员工有 3 人,平均月薪为 8200 。以下查询统计了每年入职的员工数量:

-- Oracle、MySQL 以及 PostgreSQL SELECT EXTRACT(YEAR FROM hire_date) AS "入职年份", COUNT(*) AS "员工数量" FROM employee GROUP BY EXTRACT(YEAR FROM hire_date) ORDER BY COUNT(*) DESC; -- Microsoft SQL Server SELECT DATEPART(YEAR, hire_date) AS "入职年份", COUNT(*) AS "员工数量" FROM employee GROUP BY DATEPART(YEAR, hire_date) ORDER BY COUNT(*) DESC; -- SQLite SELECT STRFTIME('%Y', hire_date) AS "入职年份", COUNT(*) AS "员工数量" FROM employee GROUP BY STRFTIME('%Y', hire_date) ORDER BY COUNT(*) DESC; 

我们在以上查询中使用了基于表达式的分组汇总,其中 EXTRACT、DATEPART 以及 STRFTIME 是不同数据库中用于提取日期信息的函数。查询返回的结果如下:

入职年份|员工数量 -------|------- 2018| 5 2000| 3 2011| 3 2002| 2 2012| 2 2017| 2 ... 

我们在使用 GROUP BY 子句进行分组时,如果分组字段中存在多个空值(NULL),它们将被分为一个组,而不是多个组。例如,以下查询按照不同奖金额统计员工的数量:

SELECT bonus AS "奖金", COUNT(*) AS "员工数量" FROM employee GROUP BY bonus; 

查询返回的结果如下:

奖金 |员工数量 --------|------- 10000.00| 3 8000.00| 1 | 16 5000.00| 2 6000.00| 1 2000.00| 1 1500.00| 1 

查询结果显示 16 位员工没有奖金,他们都被分到了同一个组。

提示:虽然 SQL 中的 NULL 和 NULL 不同,但是 GROUP BY 子句会将多个 NULL 值分为一组,也就是执行分组操作的时候认为它们相等。

常见语法问题

初学者在使用分组汇总操作时经常会犯的一个错误就是,在 SELECT 列表中使用了 GROUP BY 子句之外的字段。例如:

-- GROUP BY 错误示例 SELECT dept_id, emp_name, AVG(salary) FROM employee GROUP BY dept_id; 

以上语句在大多数数据库中都会返回一个类似的错误:emp_name 字段没有出现在 GROUP BY 子句或者聚合函数中。

这个错误的原因在于,我们想要按照部门进行分组,但是每个部门包含多名员工,数据库无法确定显示哪个员工的姓名。这是一个逻辑上的错误,而不是数据库实现的问题。

注意:MySQL 通过 sql_mode 参数 ONLY_FULL_GROUP_BY 控制该行为,默认遵循 SQL 标准;但是如果禁用该参数,以上示例将不会报错,而是随机返回一个员工姓名。以上示例在 SQLite 中也不会报错,而是随机返回一个员工姓名。

再次过滤数据

我们通常使用 WHERE 子句进行数据过滤,但是如果需要对分组汇总的结果进行过滤,是不是也可以使用 WHERE 子句实现呢?以下语句统计了每个部门的平均月薪,然后返回平均月薪大于 10 000 的部门:

-- 使用 WHERE 子句进行数据过滤的错误示例 SELECT dept_id, AVG(salary) FROM employee WHERE AVG(salary) > 10000 GROUP BY dept_id; 

以上语句在 5 种数据库中都返回了类似的错误信息:WHERE 子句中不允许使用聚合函数。

这个错误的原因在于,WHERE 子句会针对 FROM 子句中的数据行进行过滤,在 WHERE子句执行时还没有进行分组汇总操作,还没有计算出 AVG(salary)函数的值,因此不允许使用聚合函数。

为了对分组汇总后的数据再次进行过滤,SQL 提供了另一个过滤数据的子句:HAVING。我们可以使用 HAVING 子句将上面的错误示例修改如下:

SELECT dept_id AS "部门编号", AVG(salary) AS "平均月薪" FROM employee GROUP BY dept_id HAVING AVG(salary) > 10000; 

其中,HAVING 子句必须与 GROUP BY 子句一起使用,并且位于 GROUP BY 子句之后,表示对 AVG(salary)函数的结果进行过滤。查询返回的结果如下:

部门编号|平均月薪 ------|------------ 1|26666. 2|13166. 

我们可以使用 WHERE 子句对表进行数据过滤,同时使用 HAVING 子句对分组结果进行过滤。例如,以下语句查询拥有 2 名以上女性员工的部门:

SELECT dept_id AS "部门编号", COUNT(*) AS "员工数量" FROM employee WHERE sex = '女' GROUP BY dept_id HAVING COUNT(*) >= 2; 

其中,WHERE 子句用于检索女性员工,GROUP BY 子句按照部门统计女性员工的数量,HAVING 子句选择数量大于或等于 2 的部门。查询返回的结果如下:

部门编号|员工数量 ------|------- 3| 2 

只有财务部(dept_id=3)中有 2 名女性员工。

提示:从性能的角度来说,我们应该尽量使用 WHERE 子句过滤掉更多的数据,而不是等到分组之后再通过 HAVING 子句进行过滤。但是如果业务需求只能基于汇总之后的结果进行过滤,那就另当别论了。

今天的文章 五种主流数据库:分组统计分享到此就结束了,感谢您的阅读。
编程小号
上一篇 2024-12-16 14:46
下一篇 2024-12-16 14:40

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/87964.html