在数据库查询中,经常需要对数据进行分组和聚合以获取有意义的统计信息。本文将介绍如何使用SQL的GROUP BY子句进行数据分组,以及如何使用聚合函数进行计算。此外,还将探讨如何使用HAVING子句对分组后的结果进行过滤。
GROUP BY子句用于根据一个或多个列的值对结果集进行分组。这通常与聚合函数(如SUM或COUNT)一起使用,以对值进行汇总。在SQL中,分组是字段的唯一组合。使用GROUP BY子句时,不是返回表中的每行,而是返回唯一的组合。
GROUP BY子句通常添加在SQL语句的WHERE子句之后。例如,如果想列出SalesOrderID,并且排除数量大于100的记录,可以使用以下SQL语句:
SELECT SalesOrderID FROM Sales.SalesOrderDetail WHERE OrderQty <= 100 GROUP BY SalesOrderID
需要注意的是,在GROUP BY子句中列出了想要汇总的列,这些列用逗号分隔。其次,这些列也必须在SELECT语句中列出;否则,语句将失败。
当执行这个语句时,并不是返回每一行过滤后的记录。只有SalesOrderID的唯一组合包含在结果中。这个语句与以下语句非常相似:
SELECT DISTINCT SalesOrderID FROM Sales.SalesOrderDetail WHERE OrderQty <= 100
但是有一个关键区别。DISTINCT修饰符只输出行的唯一组合,而使用GROUP BY语句时,可以基于每个唯一组合的底层过滤行计算值。
聚合函数,如SUM,用于对一组行执行计算。这些函数通常在由GROUP BY子句定义的一组值上操作。如果没有GROUP BY子句,通常理解为聚合函数应用于所有过滤后的结果。
一些最常见的聚合函数包括:
这些函数可以单独使用,也可以与GROUP BY子句一起使用。单独使用时,它们在整个表上操作;但是,当与GROUP BY一起使用时,它们的计算会在每次分组变化时“重置”。以这种方式,它们充当子总计。
聚合意味着将个体部分整合成一个整体。聚合函数是作用于多行并返回结果的函数。
例如,可以使用SUM函数来计算订单详情的总金额:
SELECT SalesOrderID, SUM(OrderQty * UnitPrice) AS TotalPrice FROM Sales.SalesOrderDetail GROUP BY SalesOrderID
甚至可以按总金额排序,以首先获得顶级订单:
SELECT SalesOrderID, SUM(OrderQty * UnitPrice) AS TotalPrice FROM Sales.SalesOrderDetail GROUP BY SalesOrderID ORDER BY TotalPrice DESC
同样,可以计算订单详情金额的平均值:
SELECT SalesOrderID, AVG(OrderQty * UnitPrice) AS AverageOrderAmount FROM Sales.SalesOrderDetail GROUP BY SalesOrderID
对于好奇的人,由于平均值是样本总和除以样本计数计算的,那么在上述语句中使用AVG与以下相同:
SELECT SalesOrderID, SUM(OrderQty * UnitPrice) / COUNT(SalesOrderID) AS AvgOrderAmount FROM Sales.SalesOrderDetail GROUP BY SalesOrderID
HAVING子句用于根据聚合函数的结果过滤分组。这使得解决诸如选择所有订单详情行数超过两个的订单这样的问题成为可能。
例如,如果想找到所有订单金额超过1000美元的订单,可以这样写:
SELECT SalesOrderID, SUM(UnitPrice * OrderQty) AS TotalPrice FROM Sales.SalesOrderDetail GROUP BY SalesOrderID HAVING SUM(UnitPrice * OrderQty) > 1000 ORDER BY TotalPrice DESC
注意,虽然可以使用别名TotalPrice在ORDER BY子句中,但HAVING子句必须使用表达式。