USE AdventureWorks2008R2;
GO
SELECT SalesOrderID, ProductID, OrderQty
,SUM(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Total'
,AVG(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Avg'
,COUNT(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Count'
,MIN(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Min'
,MAX(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Max'
FROM Sales.SalesOrderDetail
WHERE SalesOrderID IN(43659,43664);
私はその条項について読みましたが、なぜそれが必要なのか理解できません。関数Over
は何をするのですか? Partitioning By
は何をしますか? Group By SalesOrderID
を書いてクエリを作成できないのはなぜですか?
あなたできるGROUP BY SalesOrderID
を使うことができます。違いは、GROUP BYでは、GROUP BYに含まれていない列の集計値しか持てないということです。
対照的に、GROUP BYの代わりにウィンドウ集約関数を使用すると、集約値と非集約値の両方を取得できます。つまり、クエリ例ではそうしていませんが、個々のOrderQty
の値と、それらの合計、カウント、平均などを、同じSalesOrderID
のグループに対して取得することができます。
これは、ウィンドウ集約が優れている理由の実例です。すべての値の合計の何パーセントかを計算する必要があるとします。ウィンドウ化された集約がなければ、まず集約された値のリストを派生させてからそれを元の行セットに戻す必要があります。
SELECT
orig.[Partition],
orig.Value,
orig.Value * 100.0 / agg.TotalValue AS ValuePercent
FROM OriginalRowset orig
INNER JOIN (
SELECT
[Partition],
SUM(Value) AS TotalValue
FROM OriginalRowset
GROUP BY [Partition]
) agg ON orig.[Partition] = agg.[Partition]
それでは、ウィンドウ集約関数を使って同じことができる方法を見てください。
SELECT
[Partition],
Value,
Value * 100.0 / SUM(Value) OVER (PARTITION BY [Partition]) AS ValuePercent
FROM OriginalRowset orig
はるかに簡単できれいですね。
OVER
句は、GROUP BY
を使用しているかどうかにかかわらず、さまざまな範囲にわたって集計を作成できる(「ウィンドウイング」)という点で強力です。
例:SalesOrderID
ごとのカウントとallのカウント
SELECT
SalesOrderID, ProductID, OrderQty
,COUNT(OrderQty) AS 'Count'
,COUNT(*) OVER () AS 'CountAll'
FROM Sales.SalesOrderDetail
WHERE
SalesOrderID IN(43659,43664)
GROUP BY
SalesOrderID, ProductID, OrderQty
別のCOUNT
sを取得します。GROUP BY
は使用しません
SELECT
SalesOrderID, ProductID, OrderQty
,COUNT(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'CountQtyPerOrder'
,COUNT(OrderQty) OVER(PARTITION BY ProductID) AS 'CountQtyPerProduct',
,COUNT(*) OVER () AS 'CountAllAgain'
FROM Sales.SalesOrderDetail
WHERE
SalesOrderID IN(43659,43664)
SalesOrderIDをGROUP BYしたいだけであれば、SELECT句にProductID列とOrderQty列を含めることはできません。
PARTITION BY句を使用して、集計関数を分割しましょう。注文の注文明細行の行番号を生成したい場合は、1つの明白で便利な例があります。
SELECT
O.order_id,
O.order_date,
ROW_NUMBER() OVER(PARTITION BY O.order_id) AS line_item_no,
OL.product_id
FROM
Orders O
INNER JOIN Order_Lines OL ON OL.order_id = O.order_id
(私の文法は少しずれているかもしれません)
その後、次のようなものに戻ります。
order_id order_date line_item_no product_id
-------- ---------- ------------ ----------
1 2011-05-02 1 5
1 2011-05-02 2 4
1 2011-05-02 3 7
2 2011-05-12 1 8
2 2011-05-12 2 1
例を挙げて説明しましょう。そうすれば、それがどのように機能するのかがわかります。
次の表DIM_EQUIPMENTがあるとします。
VIN MAKE MODEL YEAR COLOR
-----------------------------------------
1234ASDF Ford Taurus 2008 White
1234JKLM Chevy Truck 2005 Green
5678ASDF Ford Mustang 2008 Yellow
SQL以下で実行
SELECT VIN,
MAKE,
MODEL,
YEAR,
COLOR ,
COUNT(*) OVER (PARTITION BY YEAR) AS COUNT2
FROM DIM_EQUIPMENT
結果は以下のようになります
VIN MAKE MODEL YEAR COLOR COUNT2
----------------------------------------------
1234JKLM Chevy Truck 2005 Green 1
5678ASDF Ford Mustang 2008 Yellow 2
1234ASDF Ford Taurus 2008 White 2
何が起こったのか見てください。
Group ByなしでYEARにカウントしてROWと一致させることができます。
下記のようにWITH句を使用しても同じ結果が得られるもう1つの興味深い方法、WITHはインラインのVIEWとして機能し、特に複雑なクエリを単純化することができます。
WITH EQ AS
( SELECT YEAR AS YEAR2, COUNT(*) AS COUNT2 FROM DIM_EQUIPMENT GROUP BY YEAR
)
SELECT VIN,
MAKE,
MODEL,
YEAR,
COLOR,
COUNT2
FROM DIM_EQUIPMENT,
EQ
WHERE EQ.YEAR2=DIM_EQUIPMENT.YEAR;
OVER句とPARTITION BYを組み合わせると、返されたクエリの行を評価して、前の関数呼び出しを分析的に行わなければならないことが示されます。インラインのGROUP BYステートメントと考えてください。
OVER (PARTITION BY SalesOrderID)
は、SUM、AVGなどのfunctionに対して、クエリから返されたレコードのサブセットを超える値を返し、そのサブセットを外部キーSalesOrderIDで割り当てることを示しています。
したがって、各SalesOrderIDのすべてのOrderQtyレコードを合計し、その列名を 'Total'とします。
これは、同じ情報を見つけるために複数のインラインビューを使用するよりもはるかに効率的な手段です。このクエリをインラインビュー内に配置し、[合計]でフィルタすることができます。
SELECT ...,
FROM (your query) inlineview
WHERE Total < 200
Query Petition
句とも呼ばれます。Group By
句と同様
構文:
関数(...)OVER(PARTITION BY col1 col3、...)
関数
COUNT()
、SUM()
、MIN()
、MAX()
などのよく知られた関数ROW_NUMBER()
、RATION_TO_REOIRT()
など)
例付きの詳細情報: http://msdn.Microsoft.com/ja-jp/library/ms189461.aspx