0

私は T-SQL を独学しており、次の例を理解するのに苦労しています..

結果セット全体またはより大きなグループ化レベルに適用されるいくつかの集計式とともに、いくつかの非集計列を表示するとします。たとえば、Sales.SalesOrderHeader テーブルからいくつかの列を表示し、すべての顧客の売上の TotalDue と比較した各売上の TotalDue の割合を計算する必要がある場合があります。CustomerID でグループ化する場合、それらの列でグループ化しない限り、Sales.SalesOrderHeader からの他の非集計列を含めることはできません。これを回避するには、派生テーブルまたは CTE を使用できます。

ここに与えられた2つの例があります...

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 テーブルで一意であると思います) でグループ化しているため、グループごとに 1 つのレコードしかないため、これも常にTotalDue 値。

CTE の例では、CustomerId でのみグループ化しています。顧客には多数の販売注文が関連付けられている可能性があるため、これらの集計値は TotalDue とは異なります。

編集

group by に含まれるフィールドの集計の説明:

値でグループ化すると、同じ値を持つすべての行がまとめられ、それらに対して集計関数が実行されます。合計が 1 の 5 つの行と、合計が 2 の合計が 3 の行があるとすると、2 つの結果行が得られます。1 つは 1 で、もう 1 つは 2 です。これらを合計すると、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 に答える