SQL COUNT 函数

SQL Server COUNT 函数是聚合函数之一,它计算并返回 SELECT 语句在表中选择的总行数(记录)。默认情况下,COUNT 函数使用 ALL 关键字。因此,它计算给定表中的所有可用行,包括 NULL 值和重复行。Microsoft SQL Server 提供了 COUNT 函数的各种组合来处理 NULL、重复项(查找不同值)、条件计数等。

例如,当您需要获取商店中产品的总数或销售评估时?或者您想查找商店中为黑色(或其他颜色)产品下的订单。您可以在这些情况下使用此 SQL COUNT 函数,或用于数据分析、报告和业务分析。

本文涵盖了 SQL Server COUNT() 函数的详细信息,包括语法、用途、不同组合、基于条件的计数以及 GROUP BY、HAVING、CASE 语句和窗口函数的组合。

SQL COUNT 函数语法

在展示 SQL Server COUNT 函数的基本和复杂示例之前,我将介绍其简单语法。下面的代码是 COUNT 函数的简单版本,您可以向其中添加 DISTINCT、GROUP BY、HAVING、CASE 等以使其更复杂。

SELECT COUNT([Column_Name] | * )
FROM [Source]
WHERE <Search_Condition>

默认情况下,它接受 * 或列名作为参数,并计算该列或表中的总记录数。以下实际示例向您展示了 COUNT 函数的一些用例,以更好地理解。对于此 SQL COUNT() 函数演示,我们将使用下面显示的数据表和 AdventureWorksDW2019。

Employee Table

SQL Server COUNT (*) 示例

COUNT(*) 返回员工表中的总记录数。它包括表中的 NULL 值和重复项。让我们来看一个示例,以更好地理解此 聚合函数

SELECT COUNT(*) AS [Total Records]
FROM [Employees]

上面的 Select 语句 查询查找 Employee 表中存在的所有记录。

15

在实际应用中,您可能需要查找通过互联网和零售商店销售的总销售额或总产品。这样,您可以检查销售报告并使用这些指标进行进一步的业务分析计算。在这种情况下,您可以使用以下两个查询来获取总数。

SELECT COUNT(*) AS TotalInternetSales
FROM FactInternetSales;

SELECT COUNT(*) AS TotalRetailerSales
FROM FactResellerSales;
60398

60855

注意:COUNT(*) 也会汇总 NULL 值和重复记录。而 (Column Name) 会考虑并汇总重复记录。

SQL COUNT (Column Name) 示例

当您使用列名而不是 * 作为参数时,COUNT 函数将返回表中值为 NOT NULL 的员工总数(并忽略 NULL 记录)。让我们通过使用多个列作为参数值来举一个例子。

SELECT COUNT([FirstName]) AS [Total Records]
FROM [Employees]
15

下面的查询计算 [DeptID] 中值为 NOT NULL 的总记录数。

SELECT COUNT(DeptID) AS [Total DepartmentIds]
FROM [Employees];
11

在第一个语句中,我们正在计算员工表中名字的总数。在这里,COUNT 函数不会将重复项视为问题,也没有 NULL 值,因此它打印的结果与 COUNT(*) 查询相同。但是,DeptID 列有四个 NULL 记录,因此结果是 11。

以下查询将计算 DimProducts 表中的总产品和有正确描述的产品。

SELECT COUNT([ProductKey]) AS TotalProducts,
COUNT(EnglishDescription) AS ProductWithDescription
FROM DimProduct;
606 | 396

使用别名

始终建议为 SQL COUNT() 函数结果使用别名列名。如果您忽略有意义的名称,您将无法识别哪个结果属于哪个列。例如,如果您观察到以下查询输出,您将无法识别每列的总行数。但是,如果您使用别名,那将是一项简单的任务。

SELECT COUNT(Education), COUNT(FirstName),
COUNT(DeptID) AS [Total Ids]
FROM [Employees]

请将上面的查询替换为带有别名列名的以下查询。

SELECT COUNT(Education) AS [Total Education],
COUNT(FirstName) AS [Total FirstName],
COUNT(DeptID) AS [Total IDs]
FROM [Employees]

如果您需要 AdventureWorks 示例,请在 FactInternetSales 表上使用以下查询。

SELECT COUNT(Product_id) AS TotalProducts,
	COUNT(Sales) AS TotalSales
FROM FactInternetSales;

SQL COUNT DISTINCT 值示例

在上面的 COUNT(Column_Name) 示例中,查询会忽略 NULL 值但会计算重复项。在 SQL Server 中,有一个 DISTINCT 关键字,如果您明确指定此关键字,查询将返回表中值为 NOT NULL 的行的唯一数量(忽略 NULL 记录)。

提示:DISTINCT 关键字用于删除指定列名中的重复项。

为了演示结果,我们在同一查询中同时使用了常规 COUNT 和 DISTINCT 关键字来比较结果。在这里,[Total Records] 返回不为 NULL 的部门 ID 的总数。[Distinct Records] 返回 [DeptID] 中存在的非重复记录的总唯一数量(通过删除重复项),这些值为 NOT NULL。

SELECT COUNT(DeptID) AS [Total Records],
 COUNT(DISTINCT DeptID) AS [Distinct Records]
  FROM [Employees]

此示例显示了普通计数和选择性计数之间的区别。为了更好地理解,我们分别选择具有普通和 DISTINCT 的多列。

SELECT COUNT(Education) AS [Total Education],
COUNT(DISTINCT Education) AS [Distinct Education],
COUNT(FirstName) AS [Total FirstName],
COUNT(DISTINCT FirstName) AS [Distinct FirstName],
COUNT(DeptID) AS [Total Ids],
COUNT(DISTINCT DeptID) AS [Distinct Ids]
FROM [Employees]

为了计算通过互联网和零售商店销售的唯一产品,您可以使用以下查询。

SELECT COUNT(DISTINCT ProductKey) AS UniqueInternetProducts
FROM FactInternetSales;

SELECT COUNT(DISTINCT ProductKey) AS UniqueResellerProducts
FROM FactResellerSales;
SQL COUNT DISTINCT Column_Name Example

COUNT ALL 示例

默认情况下,SQL Server COUNT 函数使用 ALL 关键字,因此无论您是否明确提及它,它都会返回与常规 Column_Name 相同的结果。以下 Server 示例显示了相同的内容。

SELECT COUNT(ALL Education) AS [Total Education],
COUNT(DISTINCT Education) AS [Distinct Education],
COUNT(ALL FirstName) AS [Total FirstName],
COUNT(DISTINCT FirstName) AS [Distinct FirstName],
COUNT(ALL DeptID) AS [Total Ids],
COUNT(DISTINCT DeptID) AS [Distinct Ids]
FROM [Employees]
Count (*) Example

SQL COUNT WHERE 子句示例

从上述语法中,您可能会看到 SQL Server 也允许您在 COUNT 函数中使用 WHERE。如果您使用 WHERE 子句,您可以过滤 SELECT 语句选择的记录。因此,您可以根据需要计算表中的一些记录。

在此示例中,我们使用 Where 子句 来累加并显示年收入大于或等于 60000 的总员工数。类似地,另一个查询将计算销售额高于(大于)100 的总员工数。

SELECT COUNT(*) AS [IncomeAbove60000]
FROM [Employees]
WHERE YearlyIncome >= 60000

SELECT COUNT(*) AS [SalesAbove100]
FROM [Employees]
WHERE Sales > 100

COUNT IS NOT NULL 示例

在此示例中,我们在 WHERE 条件中使用了 IS NOT NULL。默认情况下,COUNT(*) 返回所有记录,但当我们使用如下特定条件时,它将计算部门 ID 不为 Null 的总客户数。

SELECT COUNT(*) AS [Total Records]
FROM [Employees]
WHERE DeptID IS NOT NULL

COUNT IS NULL 示例

与上面类似,如果我们使用 SQL Server IS NULL,该函数将忽略常规非 NULL 值并计算表中 NULL 记录的总数。

SELECT COUNT(*) AS [Total Records]
FROM [Employees]
WHERE DeptID IS NULL

上面的示例提供了有关使用 WHERE 子句的思路。但是,以下实际示例可帮助您了解实际优势。例如,以下查询将计算 2011 年发生的互联网销售总数。

SELECT COUNT(*) AS SalesIn2013 
FROM FactInternetSales
WHERE YEAR([OrderDate]) = 2013;

以下查询将查找 2012 年 1 月至 12 月之间发生的所有订单。您可以根据需要将日期替换为月份或季度。

SELECT COUNT(*) AS total_orders 
FROM FactInternetSales
WHERE OrderDate BETWEEN '2012-01-01' AND '2012-12-31';

SQL Server COUNT GROUP BY 子句示例

在任何聚合函数中,GROUP BY 子句都起着至关重要的作用,因为它会对相似的项进行分组。接下来,COUNT() 函数按组进行计数,而不是按整个表进行计数。

在大多数情况下,我们通常会查找属于特定地区、国家、城市等的客户数量。为了处理这些情况,我们使用 GROUP BY 子句按地区、职业、教育、州等对客户进行分组。接下来,我们使用此 COUNT 函数查找该组中的客户数量。例如,以下两个查询将查找属于类别和城市的客户。

查找按类别划分的总订单

SELECT ProductCategory , COUNT(*) as TotalOrders 
FROM Orders GROUP BY ProductCategory;

类似地,以下查询将查找按城市和产品类别划分的总客户数。

SELECT City, ProductCategory, COUNT(*) as TotalCustomers 
FROM Sales
GROUP BY city, ProductCategory;

让我们不要依赖随机示例,而是看一下实际示例,使用员工表。以下查询使用 Education 列对员工进行分组。接下来,它查找属于每个教育组的员工总数。

SELECT Education, COUNT(*) AS [Total Records]
FROM [Employees]
GROUP BY Education

这是展示 GROUP BY 子句和 SQL COUNT() 函数的另一个示例。在此示例中,我们将其与常规(包括重复项)和 DISTINCT 记录一起使用,通过在多个列上应用函数和 group by 子句来属于每个教育组。

SELECT Education, COUNT(FirstName) AS [Total FirstName],
COUNT(DISTINCT FirstName) AS [Distinct Name],
COUNT(EmpID) AS [Total Ids],
COUNT(DeptID) AS [Total DeptIds]
FROM [Employees]
GROUP BY Education

下面的查询将通过连接 AdventureWorksDW 数据库中的 FactInternetSales、DimProduct、DimProductSubcategory 和 DimProductCategory 表来计算每个产品类别的总销售额。

SELECT cat.EnglishProductCategoryName AS Category, COUNT(*) AS SalesCount
FROM FactInternetSales fact
JOIN DimProduct prod ON fact.ProductKey = prod.ProductKey
JOIN DimProductSubcategory sub
ON prod.ProductSubcategoryKey = sub.ProductSubcategoryKey
JOIN DimProductCategory cat ON sub.ProductCategoryKey = cat.ProductCategoryKey
GROUP BY cat.EnglishProductCategoryName;
COUNT GROUP BY HAVING Example

SQL COUNT WITH GROUP BY HAVING 子句

如果您想检查聚合数据上的条件,那么您必须将 HAVING ClauseGroup By Statement 一起使用。通常,我们可能需要订单超过一定数量的客户或订单数量有阈值的邮政编码。在这些情况下,我们必须按邮政编码或城市对销售额进行分组,然后使用 HAVING 子句对客户组进行过滤。例如,以下查询将按其教育程度对客户进行分组,并计算 EmpID 大于 1 的每个组中的记录数(过滤组)。

SELECT Education, COUNT(FirstName) AS [Total FirstName],
COUNT(DISTINCT FirstName) AS [Distinct Name],
COUNT(EmpID) AS [Total Ids],
COUNT(DeptID) AS [Total DeptIds]
FROM [Employees]
GROUP BY Education
HAVING COUNT(EmpID) > 1

最后一行代码将检查 Employee ID 的总数是否大于一。如果为 True,则会显示相应的记录。

以下查询与 GROUP BY 示例相同。但是,我们通过应用 (HAVING COUNT(*) > 10000) 的过滤条件来限制记录。因此,它将查找销售额超过 10000 的产品类别。

SELECT cat.EnglishProductCategoryName AS Category, COUNT(*) AS SalesCount
FROM FactInternetSales fact
JOIN DimProduct prod ON fact.ProductKey = prod.ProductKey
JOIN DimProductSubcategory sub ON prod.ProductSubcategoryKey = sub.ProductSubcategoryKey
JOIN DimProductCategory cat ON sub.ProductCategoryKey = cat.ProductCategoryKey
GROUP BY cat.EnglishProductCategoryName
HAVING COUNT(*) > 10000;
SQL Server COUNT Function with GROUP BY and HAVING Clause

SQL Server COUNT 函数 ORDER BY 子句

您可以在 ORDER BY 子句中使用此 COUNT 函数按升序或降序对值进行排序。下面的查询按教育程度打印员工表分组的总记录数。接下来,Order By Clause 将根据名字结果的 Distinct 记录按降序对这些查询结果进行排序。

SELECT Education, COUNT(FirstName) AS [Total FirstName],
COUNT(DISTINCT FirstName) AS [Distinct Name],
COUNT(DeptID) AS [Total DeptIds]
FROM [Employees]
GROUP BY Education
ORDER BY COUNT(DISTINCT FirstName) DESC
COUNT ORDER BY Example

下面的代码将连接 DimGeography 和 FactInternetSales,为每个国家计算总销售额,并按国家名称排序。

SELECT Geo.EnglishCountryRegionName AS Country, 
COUNT(*) AS SalesCount
FROM FactInternetSales AS Fact
INNER JOIN DimGeography AS Geo
ON Geo.[SalesTerritoryKey] = Fact.[SalesTerritoryKey]
GROUP BY Geo.EnglishCountryRegionName
ORDER BY Geo.EnglishCountryRegionName

COUNT 与 LIKE 操作符

您可以使用 SQL COUNT() 函数以及 LIKE 操作符来执行通配符模式匹配。如果您不知道全名,或者想要城市名称以 C 开头的客户计数或其他什么,您可以使用它。例如,下面的查询将查找并计算 DimCustomer 中名字以 J 开头的客户总数。

SELECT COUNT(*) AS CustomersJ
FROM DimCustomer
WHERE FirstName LIKE 'J%';

SQL COUNT 函数与 CASE WHEN

如果您将 COUNT 函数与 CASE WHEN 语句一起使用,它允许您计算与 CASE 中指定的特定表达式匹配的记录总数。当您想计算销售额或订单值在不同阈值(范围)内的客户时,这非常有用。例如,下面的查询将计算销售额小于 600、介于 600 和 2000 之间以及销售额在 2000 和 4500 之间的总员工数。以计算每个案例中有多少员工。请记住,有一个记录大于 4500。

SELECT 
COUNT( CASE WHEN [Sales] < 600 THEN EmpID END) AS 'Low Performers'
WHEN [Sales] > 600 AND [Sales] < 2000 THEN EmpID END) AS 'Average Performers'
WHEN [Sales] >= 2000 AND [Sales] < 4500 THEN EmpID END) AS 'Good Performers'
FROM [Employees]

类似地,下面的查询将计算 DimCustomer 表中年龄大于 25 的客户总数。如果条件为 TRUE,则返回 1;否则,返回 NULL。众所周知,COUNT 函数不考虑 NULL 值。因此,输出将是非 NULL 客户,其年龄大于 25。

SELECT COUNT(CASE WHEN DATEDIFF(yyyy, [BirthDate], GETDATE()) > 25 THEN 1 ELSE NULL END) AS TotalAdults 
FROM DimCustomer;

SELECT COUNT(CASE WHEN DATEDIFF(yyyy, [BirthDate], GETDATE()) > 50 THEN 1 ELSE NULL END) AS TotalAdults
FROM DimCustomer;
SQL COUNT Function CASE WHEN Example

JOIN 示例

如果您观察到我们针对 AdventureWorksDW 编写的上述查询,您会发现我们执行了多个连接。为了理解连接,我们使用此部分与两个简单表进行演示并显示结果。

将 COUNT 函数与 Joins 一起使用可以帮助您计算多个表的记录。在此示例中,我们使用 Inner Join 连接 Employee 和 Department 表。接下来,我们计算按部门名称分组的总记录。

SELECT E.DeptID, dep.DepartmentName,
COUNT(*) AS [Total Records]
FROM [Employees] E
INNER JOIN Department dep ON E.DeptID = dep.DeptID
GROUP BY E.DeptID, dep.DepartmentName

这是展示 Joins 和此 SQL COUNT 函数的另一个示例。

SELECT E.Education, dep.DepartmentName,
COUNT(*) AS [Total Records]
FROM [Employees] E
INNER JOIN Department dep ON E.DeptID = dep.DeptID
GROUP BY E.Education, dep.DepartmentName
ORDER BY Education

多个表示例

您可以在多个表中使用此 Count 函数。下面的查询将计算 Employee 表和 Department 表中的所有记录。

-- Multiple Tables Example

SELECT 
 (SELECT COUNT(*) 
 FROM [Employees]
 ) AS [Total Employees],
 (SELECT COUNT(*) 
 FROM [Department]
 ) AS [Total Departments]
Using Multiple Tables Example

COUNT 与 SUM 和 AVG 一起使用

此示例显示了我们如何使用 SQL COUNT 函数以及 SUM() 和 AVG() 等其他聚合函数来计算总和和平均值。它首先按教育资格对员工进行分组,然后计算每个组中的总员工数、他们的销售额总和和平均值。

SELECT Education, COUNT(*) AS Employees, 
SUM(Sales) AS Sale, AVG(Sales) AS Average
FROM [Employees]
GROUP BY Education

结果将是

教育员工销售平均
学士410596.522649.13
教育29288.584644.29
研究生学历22294.521147.26
高中12319.992319.99
硕士学位24640.982320.49
部分大学1699.0982699.0982
部分高中373.4824.4933

使用窗口函数

下面的示例查询将使用窗口函数计算每个客户的订单数。

SELECT cust.CustomerKey, cust.FirstName + cust.LastName AS Name,
fact.SalesOrderNumber, fact.OrderDate,
COUNT(s.SalesOrderNumber) OVER (PARTITION BY cust.CustomerKey) AS OrdersPerCustomer
FROM FactInternetSales fact
JOIN DimCustomer cust ON fact.CustomerKey = cust.CustomerKey
ORDER BY cust.CustomerKey, fact.OrderDate;

常见的 SQL COUNT 错误及其修复方法

  1. 如果您需要表中的总行数,请使用 COUNT(*)。而不是这个,如果您使用 COUNT(ColumnName),它不会在总数中计算 NULL 记录,并且如果该特定列中有许多 NULL,您将得不到预期的数字。
  2. 使用 DISTINCT 关键字时,请始终在其后跟列名,因为它不支持 *。例如,SELECT COUNT(DISTINCT *) 是错误的。但是,SELECT COUNT(DISTINCT Email Address) FROM employee 是正确的。
  3. 在使用 GROUP BY 时请务必小心。您必须将所有未作为聚合函数(COUNT)一部分选取的列放在 GROUP BY 中。例如,SELECT education, COUNT() FROM employees 会返回错误。但是,SELECT education, COUNT() FROM employees GROUP BY education; 将是正确的格式。
  4. 在 SQL Server 中,不允许在 WHERE 子句中使用聚合 COUNT 函数来过滤数据。在这种情况下,请使用 HAVING 子句,它允许使用任何聚合函数。例如,如果将 WHERE 条件添加到前面的示例中,它会引发错误。
-- ERROR
SELECT education, COUNT(*) FROM employees
GROUP BY education WHERE COUNT(*) > 10

--CORRECT Approach
SELECT education, COUNT(*) FROM employees
GROUP BY education HAVING COUNT(*) > 10