系列
这篇文章是阶梯系列的一部分:通向T—SQL DML的阶梯。
通过使用SQL Server的Transact-SQL (T-SQL)方言,这个阶梯将为您提供如何使用SQL Server表数据的基本理解。DML是数据处理语言,是处理数据的语言的方面。它包括语句选择、插入、更新和删除。这个阶梯将提供一些SQL语言的历史和一些关于集合理论的一般概念。每个级别都将建立在之前的级别上,所以当你完成时,你将很好地理解如何从SQL Server中选择和修改数据。
在阶梯6中,我向你展示了如何使用ORDER BY子句对数据进行排序。这使你可以根据单个或多个列对详细的记录进行排序。如果你希望在特定记录中查看数据,那么详细的数据就非常好,但是有时候你需要将详细的数据汇总到汇总值中。你可以使用GROUP BY子句完成的数据来总结。
有两种类型的GROUP BY子句。一种被称为简单的GROUP BY子句,另一种则提供了简单的概括,称为一般 GROUP BY子句。这两种类型的主要区别是简单的GROUP BY子句只包含GROUP BY子句,而一般 GROUP BY子句包含其他操作符,如汇总和多维数据集。
在本文中,我将介绍如何使用简单的group BY子句对数据进行分组。在后续的一篇文章中,我将要讨论更复杂的一般 GROUP BY子句。
简单的GROUP BY子句
使用简单GROUP BY子句可以根据单个列、多个列或表达式聚合数据。根据GROUP BY子句中指定的列和表达式,只对每个惟一的值返回一个汇总行。当SQL Server通过子句处理一个组时,它通过惟一的列或表达式值对详细记录进行分组,然后根据选择列表中包含的聚合函数对每个集合进行总结。
为了更好地理解如何使用GROUP BY子句,让我们假设你有一个表,其中包含了不同的商店的详细销售信息,你希望通过存储来总结总销售额。你可以使用GROUP BY子句来聚合每个商店的总销售额。在本例中,要分组的唯一列是存储名称,而要聚合的列是销售额。你的结果将显示每个惟一的存储名的其中一行,并且每个存储的行将包含该存储内容的销售额之和。
通过查询,SQL Server在哪些列可以包含在一个组的选择列表中有一些限制。查询组的选择列表中指定的每一列都需要归入以下类别之一:
l 在GROUP BY子句中指定的列
l 在GROUP BY子句中指定的表达式
l 从聚合函数返回的值
如果一个列不属于这些类别之一,那么当你试图通过查询并运行你的组时,你就会得到一个错误的信息。注意,GROUP BY子句中包含的列或表达式不需要出现在select列表中。
让我通过几个示例来帮助演示如何使用简单GROUP BY子句来获得汇总值。
简单的GROUP BY子句的示例
为了演示如何使用一个简单的GROUP BY子句,我构建了一些示例数据,并提供了一个脚本来创建我的示例数据,这样我们就可以运行本文提供的示例代码。使用清单1中的脚本构建并填充示例表。
SET NOCOUNT ON;
-- Create Sales Table
CREATE TABLE dbo.SalesTransaction
(Id INT IDENTITY PRIMARY KEY
,CustomerName VARCHAR(65)
,TotalSalesAmount money
,SalesTypeDesc VARCHAR(200)
,SalesDateTime DATETIME
,StoreName VARCHAR(100));
-- Add data to Sales Table
INSERT INTO dbo.SalesTransaction
VALUES (‘John Smith‘, 124.23,‘Software‘,‘09/22/2011 11:51:12 AM‘,‘The Software Outlet‘);
INSERT INTO dbo.SalesTransaction
VALUES (‘Jack Thomas‘, 29.56,‘Computer Supplies‘,‘09/23/2011 10:21:49 AM‘,‘The Software Outlet‘);
INSERT INTO dbo.SalesTransaction
VALUES (‘Sue Hunter‘, 89.45,‘Computer Supplies‘,‘09/23/2011 2:51:56 AM‘,‘The Software Outlet‘);
INSERT INTO dbo.SalesTransaction
VALUES (‘Karla Johnson‘, 759.12,‘Software‘,‘09/23/2011 2:54:37 PM‘,‘The Software Outlet‘);
INSERT INTO dbo.SalesTransaction
VALUES (‘Gary Clark‘, 81.51,‘Software‘,‘09/22/2011 11:08:52 AM‘,‘Discount Software‘);
INSERT INTO dbo.SalesTransaction
VALUES (‘Scott Crochet‘, 12345.78,‘Computer Supplies‘,‘09/23/2011 3:12:37 PM‘,‘Discount Software‘);
INSERT INTO dbo.SalesTransaction
VALUES (‘Sheri Holtz‘, 12.34,‘Software‘,‘09/23/2011 10:51:42 AM‘,‘Discount Software‘);
INSERT INTO dbo.SalesTransaction
VALUES (‘Mary Lee‘, 101.34,‘Software‘,‘09/23/2011 09:37:19 AM‘,‘Discount Software‘);
INSERT INTO dbo.SalesTransaction
VALUES (‘Sally Davisson‘, 871.12,‘Software‘,‘09/22/2011 05:21:28 PM‘,‘Discount Software‘);
INSERT INTO dbo.SalesTransaction
VALUES (‘Rod Kaplan‘, 2345.19,‘Computer Supplies‘,‘09/23/2011 5:01:11 PM‘,‘Discount Software‘);
INSERT INTO dbo.SalesTransaction
VALUES (‘Sandy Roberts‘, 76.38,‘Books‘,‘09/23/2011 4:51:57 PM‘,‘Computer Books and Software‘);
INSERT INTO dbo.SalesTransaction
VALUES (‘Marc Trotter‘, 562.94,‘Software‘,‘09/23/2011 6:51:43 PM‘,‘Computer Books and Software‘);
1:创建示例数据的脚本
如果看1中的脚本,就会发现我创建了dbo..Sales Transaction table。之后,我会将一些记录插入到这个表中。我将使用这个表来演示如何使用一个简单的GROUP BY子句来聚合数据。
按单个列分组
使用清单1创建的示例表,第一个示例将使用GROUP BY子句来基于单个列汇总数据。清单2中的示例总结了基于StoreName列的示例数据。
USE tempdb;
GO
SELECT StoreName
,SUM(TotalSalesAmount) AS StoreSalesAmount
FROM dbo.SalesTransaction
GROUP BY StoreName;
清单2:基于单个列的组
当清单2中的代码在我的示例表中执行时,将返回报告1中的以下汇总行。
StoreName StoreSalesAmount
------------------------------------------ ----------------
Computer Books and Software 639.32
Discount Software 15757.28
The Software Outlet 1002.36
报告1:基于单个列汇总样本数据。
如果看报告1中的输出结果,可以看到,只有一个聚合行被返回,来获得多个独特的StoreName值。每个记录的StoreSalesAmount都是通过使用SUM函数将每个商店的销售记录的TotalSalesAmount列相加来计算的。
分组由多个列
需要开发一份报告时,其中的数据需要把多个列进行分组。为了实现这一点,您需要做的就是在GROUP BY子句中添加额外的列。当在GROUP BY子句中添加多个列时,SQL Server将根据GROUP BY子句中各列的惟一组合值对它们行进行聚合。在清单3中,我通过在GROUP by子句中添加第二列,扩展了清单2中的查询范围。
USE tempdb;
GO
SELECT StoreName, SalesTypeDesc
,SUM(TotalSalesAmount) AS StoreSalesAmount
FROM dbo.SalesTransaction
GROUP BY StoreName, SalesTypeDesc;
清单3:基于单个列的组
当我根据示例数据运行清单3中的代码时,我得到了报告2中的结果。
StoreName SalesTypeDesc StoreSalesAmount
---------------------------- ------------------ ----------------
Computer Books and Software Books 76.38
Discount Software Computer Supplies 14690.97
The Software Outlet Computer Supplies 119.01
Computer Books and Software Software 562.94
Discount Software Software 1066.31
The Software Outlet Software 883.35
报告2:运行清单1的输出
在报告2中,您可以看到StoreSalesAmount现在是StoreName和SalesTypeDesc总级别。还要注意,返回的聚合一行不是按照GROUP BY子句中列的顺序排序的。如果希望汇总数据以StoreName的顺序出现,那么就需要在SELECT语句中包含order BY子句。我将订单添加到清单3中的代码会返回StoreName订单中的汇总数据。
Using an Expression in the GROUP BY Clause
有时,你可能希望将数据分组,而不是特定的列或列集。例如,你可能希望根据一些VARCHAR列的前几个字符,或者仅仅是日期,或DATETIME列的月份来总结你的数据。SQL Server允许你在GROUP BY子句中指定表达式来完成此操作。表达式可以是基于正在聚合的详细记录集中的列的任何有效表达式。为了演示如何在GROUP BY子句中使用表达式,请查看清单4中的代码。
USE tempdb;
GO
SELECT CONVERT(CHAR(10),SalesDateTime,101) AS SalesDate
,SUM(TotalSalesAmount) AS TotalSalesAmount
FROM dbo.SalesTransaction
GROUP BY CONVERT(CHAR(10),SalesDateTime,101);
Listing 4: GROUP BY based on Single columns
在清单4中,SELECT语句将基于表达式的数据分组,在本例中为转换函数。如果在GROUP BY子句中使用表达式,则必须在SELECT列表中使用相同的表达式。CONVERT函数将解析SalesDateTime列,并只返回该列的日期部分。使用GROUP BY子句中的CONVERT函数,可以根据不同销售记录的实际日期对销售数据进行汇总。通过这样做,我可以总结我的示例,以获得所有商店的总销售额,如报告3所示。
SalesDate TotalSalesAmount
---------- ----------------
09/22/2011 1076.86
09/23/2011 16322.10
Report 3: Output when summarizing data based on expression
使用表达式可以让你以编程方式识别您的详细数据的哪些部分将被用于聚合数据。
HAVING Clause
如果你使用GROUP BY子句聚合数据,你可能希望不返回所有聚合的值。相反,你可能只想返回聚合值的一个子集。可以使用HAVING子句来选择性地识别你想要从组中返回的聚合值。
通常,当我们选择数据时,我们使用WHERE子句来限制返回的行。惟一的问题是WHERE子句操作行值,而不是聚合值。因此,WHERE子句不能使用GROUP by子句创建的聚合值。但是,在GROUP BY子句后面添加一个HAVING子句为您提供了一种指定条件来确定您想要返回的特定汇总值的方法。为了更好地理解这一点,我来举几个例子。
在查看商店销售数据时,有一个常见的条款可能用于确定没有达到特定销售限额的商店。如果你想找到所有不满足最低销售金额的商店,你可以使用清单5中的代码来实现。
USE tempdb;
GO
SELECT StoreName
,SUM(TotalSalesAmount) AS StoreSalesAmount
FROM dbo.SalesTransaction
GROUP BY StoreName
HAVING SUM(TotalSalesAmount) < 1000.00;
Listing 5: Restricting result set by using HAVING clause
在清单5中,我将结果集限制为那些累计总销售额小于1000.00的商店。在我这个简单的例子中,你会发现“计算机书籍和软件”的StoreName是唯一一个没有达到$1000.00的销售配额数量的商店。
HAVING子句可以用于未聚合的列。如果你希望根据GROUP BY子句中使用的任何列的特定值来限制返回的行,那么你也可以这样做,清单6演示了这一点。
USE tempdb;
GO
SELECT StoreName
,SUM(TotalSalesAmount) AS StoreSalesAmount
FROM dbo.SalesTransaction
GROUP BY StoreName
HAVING StoreName LIKE ‘%Outlet%‘
OR StoreName LIKE ‘%Books%‘;
Listing 6: Restricting result set based on GROUP BY column
在清单6中,我只希望看到在他们的商店名称中有“Outlet”或“Books”的商店的汇总数据,这个例子还表明在HAVING子句中可以有多个条件。另一种方法是考虑WHERE和HAVING之间的区别,即WHERE子句在数据被聚合之前过滤掉数据行,而HAVING子句在应用程序组之后过滤出聚集的行。
Summarizing Data with the Simple GROUP BY Clause
在本文中,我向你展示了如何使用简单的GROUP BY子句来总结你的数据。我讨论了如何使用单个列、多个列以及GROUP BY子句中的表达式来总结详细数据。通过使用我所演示的内容,你现在应该能够构建一个简单的GROUP By子句来总结你的数据,并且可以选择使用have来过滤汇总数据。
在我的下一篇文章中,我将扩展我对GROUP BY子句的讨论。在这篇后续文章中,我将向你展示如何使用多维数据集和ROLLUP操作符来生成额外的汇总数据,如子总数和总值。
原文:https://www.cnblogs.com/hawking-520/p/8910466.html