SQL OVER()句-いつ、なぜ役立つのですか?


169
    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ですか?


30
使用するRDBMSに関係なく、Postgresチュートリアルが役立つ場合があります。例があります。助けて頂きました。
Andrew Lazarus

回答:


144

あなたはすることができます使用しますGROUP BY SalesOrderID。違いは、GROUP BYでは、GROUP BYに含まれていない列の集計値しか持てないことです。

対照的に、GROUP BYの代わりにウィンドウ化された集計関数を使用すると、集計値と非集計値の両方を取得できます。つまり、サンプルクエリではそうしていませんがOrderQty、同じSalesOrderIDsのグループの個々の値と、それらの合計、カウント、平均などの両方を取得できます。

ウィンドウ化された集計が優れている理由の実例を次に示します。すべての値の合計のパーセントを計算する必要があるとします。ウィンドウ化された集計がない場合は、まず集計された値のリストを取得し、それを元の行セットに結合する必要があります。つまり、次のようになります。

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

ずっと簡単でクリーンですね。


68

このOVER句は、使用するかどうかに関係GROUP BYなく、さまざまな範囲(「ウィンドウ」)で集計を行うことができるという点で強力です。

例:SalesOrderIDカウント数とすべての数を取得する

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

異なるCOUNTsを取得します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)

47

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

42

例を挙げて説明すると、それがどのように機能するかがわかります。

次のテーブル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

何が起こったのか見てください。

YEARのGroup Byなしでカウントし、ROWと一致させることができます。

以下のようにWITH句を使用すると同じ結果が得られる別の興味深い方法、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;

17

OVER句をPARTITION BYと組み合わせると、前の関数呼び出しは、返されたクエリの行を評価することによって分析的に実行する必要があることを示します。インラインのGROUP BYステートメントと考えてください。

OVER (PARTITION BY SalesOrderID) SUM、AVGなどの関数の場合は、クエリから返されたレコードのサブセットの値OVERを返し、そのサブセットは外部キーSalesOrderIDによってPARTITIONを返すと述べています。

したがって、各UNIQUE SalesOrderIDのすべてのOrderQtyレコードを合計し、その列名を「合計」と呼びます。

これは、複数のインラインビューを使用して同じ情報を見つけるよりもはるかに効率的な方法です。このクエリをインラインビュー内に配置して、Totalでフィルタリングできます。

SELECT ...,
FROM (your query) inlineview
WHERE Total < 200

2
  • Query Petition節とも呼ばれます。
  • Group By条項と同様

    • データをチャンク(またはパーティション)に分割する
    • パーティション境界で区切る
    • 関数はパーティション内で実行されます
    • パーティング境界を越えるときに再初期化されます

構文:
function(...)OVER(PARTITION BY col1 col3、...)

  • 関数

    • などの馴染みの機能COUNT()SUM()MIN()MAX()、など
    • だけでなく、新機能(例えばROW_NUMBER()RATION_TO_REOIRT()など)


例付きの詳細:http : //msdn.microsoft.com/en-us/library/ms189461.aspx


-3
prkey   whatsthat               cash   
890    "abb                "   32  32
43     "abbz               "   2   34
4      "bttu               "   1   35
45     "gasstuff           "   2   37
545    "gasz               "   5   42
80009  "hoo                "   9   51
2321   "ibm                "   1   52
998    "krk                "   2   54
42     "kx-5010            "   2   56
32     "lto                "   4   60
543    "mp                 "   5   65
465    "multipower         "   2   67
455    "O.N.               "   1   68
7887   "prem               "   7   75
434    "puma               "   3   78
23     "retractble         "   3   81
242    "Trujillo's stuff   "   4   85

これがクエリの結果です。ソースとして使用されるテーブルは、最後の列がないのと同じ例外です。この列は3番目の列の移動合計です。

クエリ:

SELECT prkey,whatsthat,cash,SUM(cash) over (order by whatsthat)
    FROM public.iuk order by whatsthat,prkey
    ;

(テーブルはpublic.iukとして移動します)

sql version:  2012

それはdbase(1986)レベルを少し超えていますが、それを完成させるのに25年以上かかるのはなぜでしょうか。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.