SQL分组指南

目录

什么是SQL分组?

SQL GROUP BY和Sum

排序分组结果

HAVING和GROUP BY

包含多个表的GROUP BY

按SUM()排序

带有表达式的GROUP BY

SQL GROUP BY与DISTINCT

结论


什么是SQL分组?

SQL中,分组是唯一的列值组合。当查询具有GROUP BY, 而不是返回满足过滤条件的每一行时,首先将值分组在一起。返回的行是列中的唯一组合。

GROUP BY的整体语法是:

SELECT   colum1, column2, column3, .. 
FROM     table1 
GROUP BY column1, column2, column3,… 

在本文中,我们将重点放在HumanResources.Employee表上。

在此示例中,我按JobTitleGender对表格进行了排序。

在这里,您可以看到小组的开始。最后一步是在语句中添加一个SQL  GROUP BY子句来创建分组。

SELECT JobTitle, MaritalStatus, COUNT(*) NumberEmployees
FROM HumanResources.Employee
GROUP BY JobTitle, MaritalStatus
ORDER BY JobTitle, MaritalStatus

你在这里看到结果:

我想让你注意几件事:

我删除了属于组或摘要的列,例如COUNT(*)select中仅允许在GROUP BY中列出的列。除了这些之外,您还可以使用聚合函数,例如SUMCOUNTMINMAXAVG

我在声明中保留了ORDER BY,因为GROUP BY不保证对组进行排序。

现在您已经很好地掌握了它的工作原理,让我们看看更多与GROUP BY的信息。

SQL GROUP BYSum

让我们做一些总结!对于更改,我们将汇总SalesOrderDetail记录。对于每个SalesOrder,让我们计算OrderTotal、一个SalesOrder的平均SalesOrderDetail总行数以及订单中的SalesOrderDetail行数。

我们将使用group bySUMAVGCOUNT函数来提供帮助。

SELECT SalesOrderID     
     ,SUM(LineTotal) AS OrderTotal
     ,AVG(LineTotal) AS AverageLineTotal
     ,COUNT(LineTotal) AS NumberOfLines
FROM Sales.SalesOrderDetail
GROUP BY SalesOrderIDORDER BY SalesOrderID;

由于每个Sales Order有一行或多行,我们将按SalesOrderID group by。查看结果:

以下是使用这些功能时需要考虑的一些提示。你可以:

  1. SQL中使用多个函数。
  2. 在表达式中包含函数。
  3. 别名表达式。

您还可以使用聚合函数创建新表达式。为了证明这一点,让我们计算平均线总计,知道平均值=线总计之和/计数。

这是使它成为这样的查询:

SELECT SalesOrderID
     ,SUM(LineTotal) AS OrderTotal
     ,COUNT(LineTotal) AS NumberOfLines
     ,SUM(LineTotal) / COUNT(LineTotal) AS AverageLineTotal
     ,AVG(LineTotal) AverageFunctionLineTotal
FROM Sales.SalesOrderDetail
GROUP BY SalesOrderID
ORDER BY SalesOrderID;

和结果。注意如何计算AverageLineTotal等于函数的值。

排序分组结果

分组不按排序顺序返回。为此,您需要包含该ORDER BY子句。将该子句添加ORDER BYSQL语句的末尾。

修改此语句,使其按SalesOrderIDCarrierTrackingNumber​​对组进行排序。

/* Answer */
SELECT SalesOrderID, CarrierTrackingNumber, COUNT(1) as NumberofLines 
FROM Sales.SalesOrderDetail 
GROUP BY SalesOrderID, CarrierTrackingNumber 
ORDER BY SalesOrderID, CarrierTrackingNumber 

HAVINGGROUP BY

HAVING 子句过滤使用GROUP BY创建的分组。该HAVING子句确定结果中是否包含分组。

WHERE过滤单个记录的子句不同,HAVING子句过滤分组;但是,请记住SQL同时包含WHEREHAVING两个进程!

在这种情况下,首先处理WHERE子句,然后过滤这些记录。然后将HAVING应用于 中指定的GROUP BY分组。

通常HAVINGGROUP BY一起使用,但如果GROUP BY不包含该子句,则将整个结果集作为一个隐式分组进行HAVING操作。

考虑我们前面的例子。在这里,我们计算OrderTotals

SELECT SalesOrderID     
     ,SUM(LineTotal) AS OrderTotal
     ,AVG(LineTotal) AS AverageLineTotal
     ,COUNT(LineTotal) AS NumberOfLines
FROM Sales.SalesOrderDetail
GROUP BY SalesOrderID
ORDER BY SalesOrderID;

假设我们需要展示总额超过100,000.00美元的大订单。我们怎么能这样做?

使用HAVING子句过滤SUM(LineTotal)

这是显示大订单的查询:

SELECT SalesOrderID     
     ,SUM(LineTotal) AS OrderTotal
     ,AVG(LineTotal) AS AverageLineTotal
     ,COUNT(LineTotal) AS NumberOfLines
FROM Sales.SalesOrderDetail
GROUP BY SalesOrderID
HAVING SUM(LineTotal) > 100000.00
ORDER BY SalesOrderID;

HAVING有什么好

HAVING子句的主要优点是它能够使用聚合函数进行GROUPS过滤。这是您不能在SELECT语句中执行的操作。

提示:如果你很难理解HAVINGWHERESELECT中的作用,我建议先了解SELECT语句的执行顺序。

包含多个表的GROUP BY

GROUP BY还可以包括来自多个表的列。在以下查询中,让我们通过ProductName计算销售额。为此,我们将SalesOrderDetail加入Product。我们joinproduct

SELECT p.Name ProductName,
    SUM(s.OrderQTY) TotalQuantitySold,
    SUM(s.LineTotal) TotalSales,
    SUM(s.OrderQTY * p.StandardCost) TotalStandardCost,
    SUM(s.LineTotal) - SUM(s.OrderQTY * p.StandardCost) GrossMargin
FROM Sales.SalesOrderDetail s
    INNER JOIN Production.Product p ON  s.ProductID = p.ProductID
GROUP BY p.Name
ORDER BY p.Name

查看两个表中的列如何参与TotalStandardCost计算。

SUM()排序

使用与上面相同的示例,请注意我可以按总数之一进行排序。在这种情况下,我们将按TotalQuantitySold进行排序。

SELECT p.Name ProductName,
    SUM(s.OrderQTY) TotalQuantitySold,
    SUM(s.LineTotal) TotalSales,
    SUM(s.OrderQTY * p.StandardCost) TotalStandardCost,
    SUM(s.LineTotal) - SUM(s.OrderQTY * p.StandardCost) GrossMargin
FROM Sales.SalesOrderDetail s
    INNER JOIN Production.Product p ON  s.ProductID = p.ProductID
GROUP BY p.Name
ORDER BY SUM(s.OrderQTY)

由于此列有别名,让我们通过按别名排序来使查询更易于阅读。

带有表达式的GROUP BY

您可以对表达式进行分组。只要SELECT列表中存在相同的表达式,就允许分组。

SELECT Year(OrderDate) OrderYear, Sum(TotalDue) YearlySales
FROM Sales.SalesOrderHeader
GROUP BY YEAR(OrderDate)
ORDER BY OrderYear

在此示例中,让我们按年份对SalesOrder总数进行分组和汇总

没有什么能阻止我们对一个或多个表达式进行分组!让我们通过Month进一步分组销售。

SELECT Year(OrderDate) OrderYear,
       Month(OrderDate) OrderMonth,
       SUM (TotalDue) MonthlySales
FROM Sales.SalesOrderHeader
GROUP BY YEAR(OrderDate), MONTH(OrderDate)
ORDER BY OrderYear, OrderMonth

在我忘记之前,看看我是如何对结果进行排序的。我使用列别名来排序而不是重复表达式。两者都是有效的,但是将我们的表达保持在最低限度确实很好!我认为它更容易阅读。如果您想知道,由于SQL操作顺序,这一切都是可能的。

这是结果。我对列进行了颜色编码,以更好地向您展示多个表达式。与前面的示例一样,在GROUP BY中使用的每个表达式也被列为一列。

SQL GROUP BYDISTINCT

在某些方面,GROUP BY类似于使用DISTINCT子句。

SELECT DISTINCT JobTitle, MaritalStatus
FROM HumanResources.Employee
ORDER BY JobTitle, MaritalStatus

使用SQL GROUP BY返回与此SQL相同的结果:

SELECT JobTitle, MaritalStatus
FROM HumanResources.Employee
GROUP BY JobTitle, MaritalStatus
ORDER BY JobTitle, MaritalStatus

DISTINCTGROUP BY之间的主要区别在于,使用GROUP BY时,您还可以汇总值。

在这里,我们包含了确定每个组有多少行的COUNT()函数:

/* Answer */
SELECT SalesOrderID, CarrierTrackingNumber, COUNT(1) as NumberofLines 
FROM Sales.SalesOrderDetail
GROUP BY SalesOrderID, CarrierTrackingNumber;

结论

使用SQL GROUP BY时,请记住以下几点:

  • SQL GROUP BY不保证按排序顺序返回组。
  • 您可以使用聚合函数,例如SUMCOUNT来汇总数据。
  • SELECT列表中的非汇总列必须与GROUP BY中列出的列匹配。

本文最初发布于SQL GROUP BY Guide - Essential SQL

https://www.codeproject.com/Articles/5326747/SQL-GROUP-BY-Guide

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值