SQLGROUPBY怎么配合聚合函数使用_SQLGROUPBY与聚合函数组合用法

GROUP BY按列分组数据,聚合函数对每组计算汇总值;WHERE在分组前筛选行,HAVING在分组后基于聚合结果筛选;NULL值被归为一组,多数聚合函数自动忽略NULL;多列分组时,数据库将所有分组列值相同的行划为一组。

SQLGROUPBY怎么配合聚合函数使用_SQLGROUPBY与聚合函数组合用法

SQL中的

GROUP BY

子句与聚合函数是数据分析的黄金搭档,简单来说,它允许你将数据行根据一个或多个列的值进行分组,然后对每个组应用聚合函数(如

COUNT

SUM

AVG

MIN

MAX

),从而计算出每个组的汇总结果。没有它,我们很难从海量数据中提炼出有意义的洞察,比如计算每个部门的员工数量,或者统计每个产品的总销售额。

要深入理解

GROUP BY

与聚合函数的协作,我们需要先搞清楚它们各自的角色。聚合函数天生就是为了处理一组数据并返回一个单一的汇总值。比如,

COUNT(*)

会计算所有行的数量,

SUM(amount)

会计算某一列的总和。但当你需要这些汇总值是基于特定分类时,

GROUP BY

就登场了。

它的基本语法是这样的:

SELECT     列1,     聚合函数(列2) FROM     表名 WHERE     条件 GROUP BY     列1 HAVING     分组后的条件 ORDER BY     排序字段;

这里,

GROUP BY 列1

告诉数据库,请把所有

列1

值相同的行归为一组。然后,

SELECT

语句中的聚合函数就会对这些分组后的数据独立执行计算。

举个例子,假设我们有一个

Orders

表,包含

CustomerID

OrderAmount

。如果我们想知道每个客户的总消费金额:

SELECT     CustomerID,     SUM(OrderAmount) AS TotalSpent FROM     Orders GROUP BY     CustomerID;

这条语句会先根据

CustomerID

把所有订单分组,然后对每个

CustomerID

组内的

OrderAmount

求和,最终返回每个客户ID及其对应的总消费。

我个人觉得,理解

GROUP BY

的精髓在于它如何改变了聚合函数的“作用域”。如果没有

GROUP BY

,聚合函数会作用于整个查询结果集(如果

WHERE

有筛选,就是筛选后的结果集),返回一个单一的总计。而有了

GROUP BY

,聚合函数的作用域就缩小到了每一个独立的分组。这种从“全局”到“局部”的视角转换,是数据分析中非常强大且常用的能力。

在使用SQL GROUP BY时,WHERE和HAVING子句有什么不同?

这个问题,我遇到过太多初学者甚至一些有经验的开发者都会搞混。简单来说,

WHERE

HAVING

都是用来筛选数据的,但它们筛选的时机和对象完全不同。

WHERE

子句是在数据被分组之前进行筛选的。它作用于原始的、未分组的行。这意味着你可以在

WHERE

子句中使用原始表中的任何列,即使这些列没有出现在

GROUP BY

SELECT

列表中。它的目的是减少要进行分组的数据量,从而提高效率,并确保只有符合条件的行才会被纳入分组计算。

比如,我们只想统计2023年之后订单的客户总消费:

SELECT     CustomerID,     SUM(OrderAmount) AS TotalSpent FROM     Orders WHERE     OrderDate >= '2023-01-01' -- 在分组前,先筛选出2023年后的订单 GROUP BY     CustomerID;

这里,

WHERE

子句先剔除了2023年之前的订单,然后再对剩下的订单按客户分组并求和。

HAVING

子句则是在数据被

GROUP BY

分组之后,并且聚合函数计算完成之后,才开始进行筛选的。它作用于每个分组的汇总结果。因此,在

HAVING

子句中,你通常会使用聚合函数的结果进行条件判断,或者使用

GROUP BY

子句中出现的列。你不能在

HAVING

子句中直接引用那些没有被分组且没有被聚合的原始列。

SQLGROUPBY怎么配合聚合函数使用_SQLGROUPBY与聚合函数组合用法

SkyReels

SkyReels是全球首个融合3D引擎与生成式AI的AI视频创作平台

SQLGROUPBY怎么配合聚合函数使用_SQLGROUPBY与聚合函数组合用法865

查看详情 SQLGROUPBY怎么配合聚合函数使用_SQLGROUPBY与聚合函数组合用法

继续上面的例子,如果我们还想找出那些总消费超过1000元的客户:

SELECT     CustomerID,     SUM(OrderAmount) AS TotalSpent FROM     Orders WHERE     OrderDate >= '2023-01-01' GROUP BY     CustomerID HAVING     SUM(OrderAmount) > 1000; -- 在分组并计算总消费后,再筛选出总消费大于1000的客户

这里,

HAVING SUM(OrderAmount) > 1000

是在每个客户的总消费(

SUM(OrderAmount)

)计算出来之后,再判断是否大于1000。

我个人的经验是,如果你想基于原始行数据进行过滤,用

WHERE

;如果你想基于聚合后的结果进行过滤,用

HAVING

。这个区分不仅是语法上的,更是逻辑上的,理解它能帮你写出更精确、更高效的SQL查询。有时候,我会看到有人尝试在

WHERE

里写

SUM(OrderAmount) > 1000

,这通常会报错,因为

WHERE

还没到聚合函数发挥作用的阶段。

SQL GROUP BY如何处理NULL值以及对聚合结果的影响?

NULL

值在数据库里总是一个有点微妙的存在,

GROUP BY

对它的处理方式也值得我们注意。当你使用

GROUP BY

子句对包含

NULL

值的列进行分组时,所有

NULL

值会被视为相等,并被归为一个单独的分组。这和我们平时在

WHERE

子句中用

IS NULL

来判断

NULL

有点类似,但在分组语境下,

NULL

们是“同类”。

举个例子,假设我们有一个

Employees

表,其中

DepartmentID

列可能包含

NULL

值(比如有些员工还没分配部门)。

SELECT     DepartmentID,     COUNT(EmployeeID) AS NumberOfEmployees FROM     Employees GROUP BY     DepartmentID;

执行这条查询后,你会看到类似这样的结果: | DepartmentID | NumberOfEmployees | |————–|——————-| | 101 | 5 | | 102 | 8 | | NULL | 3 |

这里,所有

DepartmentID

NULL

的员工被归到了一个名为

NULL

的组中,并且

COUNT(EmployeeID)

计算出了这个组里有3名员工。这通常是符合我们预期的,因为我们可能需要知道那些“未分配部门”的员工数量。

但是,

NULL

值对聚合函数的影响就更复杂一些,因为它取决于具体的聚合函数。

  • COUNT(column_name)

    : 这个函数会忽略

    NULL

    值。也就是说,它只计算指定列中非

    NULL

    值的行数。如果你想计算包括

    NULL

    值在内的所有行数,应该使用

    COUNT(*)

    COUNT(1)

    • 例如,
      COUNT(DepartmentID)

      会忽略

      DepartmentID

      NULL

      的行,而

      COUNT(*)

      则会计算所有行。

  • SUM()

    AVG()

    MIN()

    MAX()

    : 这些聚合函数在计算时,也会自动忽略

    NULL

    值。它们只对非

    NULL

    值进行计算。

    • 比如,
      AVG(Salary)

      会计算所有有薪水记录的员工的平均薪水,而不会把

      NULL

      薪水的员工纳入计算,也不会把

      NULL

      当作0来处理。这通常是合理的,因为

      NULL

      表示“未知”或“不适用”,而不是0。

所以,在处理

NULL

值时,我通常会特别注意

COUNT()

的行为差异,以及其他聚合函数对

NULL

的默认忽略。如果你的业务逻辑需要将

NULL

视为某个特定值(比如将

NULL

部门视为“未分类”,或者将

NULL

薪水视为0),你可能需要在聚合之前使用

COALESCE()

ISNULL()

等函数来转换

NULL

值。这种预处理能确保聚合结果完全符合你的业务需求,避免因为

NULL

的默认行为导致数据分析的偏差。

在多列上使用SQL GROUP BY时,数据分组逻辑是怎样的?

当我们需要更细粒度的分组时,

GROUP BY

允许我们指定多个列。这时候,分组的逻辑会变得更加层级化,或者说,是组合式的。数据库会把所有在

GROUP BY

子句中指定的列的值都相同的行视为一个组。

想象一下,你有一个

Sales

表,包含

Region

(地区)、

ProductCategory

(产品类别)和

SalesAmount

(销售额)。如果你想知道每个地区每个产品类别的总销售额:

SELECT     Region,     ProductCategory,     SUM(SalesAmount) AS TotalSales FROM     Sales GROUP BY     Region,     ProductCategory;

这条查询的执行逻辑是这样的:

  1. 首先,数据库会找到所有
    Region

    ProductCategory

    组合都相同的行。

  2. 例如,所有“华东地区”且“电子产品”的销售记录会形成一个组。
  3. 所有“华东地区”且“家居用品”的销售记录会形成另一个组。
  4. 所有“华北地区”且“电子产品”的销售记录又会形成一个组。

go 作用域 聚合函数 lsp sql NULL count select 对象 作用域 数据库 数据分析

上一篇
下一篇