0

我正在自学 T-SQL,并且正在努力理解以下示例。

假设您想要显示几个非聚合列以及一些应用于整个结果集或更大分组级别的聚合表达式。例如,您可能需要显示 Sales.SalesOrderHeader 表中的几列,并计算每个销售的 TotalDue 与所有客户销售的 TotalDue 的百分比。如果按 CustomerID 分组,则不能包含 Sales.SalesOrderHeader 中的其他非聚合列,除非按这些列分组。为了解决这个问题,您可以使用派生表或 CTE。

这里给出了两个例子......

SELECT c.CustomerID, SalesOrderID, TotalDue, AvgOfTotalDue,
TotalDue/SumOfTotalDue * 100 AS SalePercent
FROM Sales.SalesOrderHeader AS soh
INNER JOIN
(SELECT CustomerID, SUM(TotalDue) AS SumOfTotalDue,
AVG(TotalDue) AS AvgOfTotalDue
FROM Sales.SalesOrderHeader
GROUP BY CustomerID) AS c ON soh.CustomerID = c.CustomerID
ORDER BY c.CustomerID;

WITH c AS
(SELECT CustomerID, SUM(TotalDue) AS SumOfTotalDue,
AVG(TotalDue) AS AvgOfTotalDue
FROM Sales.SalesOrderHeader
GROUP BY CustomerID)
SELECT c.CustomerID, SalesOrderID, TotalDue,AvgOfTotalDue,
TotalDue/SumOfTotalDue * 100 AS SalePercent
FROM Sales.SalesOrderHeader AS soh
INNER JOIN c ON soh.CustomerID = c.CustomerID
ORDER BY c.CustomerID;

为什么这个查询不产生相同的结果..

SELECT CustomerID, SalesOrderID, TotalDue, AVG(TotalDue) AS AvgOfTotalDue,
    TotalDue/SUM(TotalDue) * 100 AS SalePercent
FROM Sales.SalesOrderHeader
GROUP BY CustomerID, SalesOrderID, TotalDue
ORDER BY CustomerID

我正在寻找有人以另一种方式解释上述示例或逻辑地逐步解释它们,以便我可以理解它们是如何工作的?

4

1 回答 1

2

此语句中的聚合(即 SUM 和 AVG)不执行任何操作:

SELECT CustomerID, SalesOrderID, TotalDue, AVG(TotalDue) AS AvgOfTotalDue,
    TotalDue/SUM(TotalDue) * 100 AS SalePercent
FROM Sales.SalesOrderHeader
GROUP BY CustomerID, SalesOrderID, TotalDue
ORDER BY CustomerID

这样做的原因是您按 TotalDue 进行分组,因此同一组中的所有记录都具有相同的字段值。对于 AVG,这意味着保证 AvgOfTotalDue 始终等于 TotalDue。对于 SUM,您可能会得到不同的结果,但是由于您还按 SalesOrderID 进行分组(我想它在 SalesOrderHeader 表中是唯一的),因此每个组只有一条记录,因此这将始终等于TotalDue 值。

在 CTE 示例中,您仅按 CustomerId 分组;由于客户可能有许多与之关联的销售订单,因此这些合计值将与 TotalDue 不同。

编辑

组中包含的字段聚合的说明:

当您按一个值分组时,具有相同值的所有行都被收集在一起,并对它们执行聚合函数。假设您有 5 行,总计 1 和 3 行,总计 2,您将得到两条结果行;一个带1s,一个带2s。现在,如果你对这些进行求和,你就有 3*1 和 2*2。现在除以该结果行中的行数(以获得平均值),您有 3*1/3 和 2*2/2;所以事情抵消了,只剩下 1 和 2。

select totalDue, avg(totalDue)
from (
    select 1 totalDue 
    union all select 1 totalDue 
    union all select 1 totalDue 
    union all select 2 totalDue 
    union all select 2 totalDue 
) x
group by totalDue


select uniqueId, totalDue, avg(totalDue), sum(totalDue)
from (
    select 1 uniqueId, 1 totalDue 
    union all select 2 uniqueId, 1 totalDue 
    union all select 3 uniqueId, 1 totalDue 
    union all select 4 uniqueId, 2 totalDue 
    union all select 5 uniqueId, 2 totalDue 
) x
group by uniqueId

可运行示例:http ://sqlfiddle.com/#!2/d41d8/21263

于 2013-09-25T22:26:24.657 回答