使用派生表和CTE显示详细信息?

时间:2013-09-25 22:17:48

标签: tsql sql-server-2012

我正在教自己T-SQL,并且正在努力理解下面的例子。

  

假设您要显示几个非聚合列   一些适用于整个结果集或a的聚合表达式   更大的分组水平。例如,您可能需要显示几个   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

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

1 个答案:

答案 0 :(得分: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