web-dev-qa-db-ja.com

前の行までの累計

ウィンドウ関数のヘルプが必要です。ウィンドウ内の合計とウィンドウ内の現在の合計を計算できることを知っています。しかし、以前の現在の合計、つまり現在の行を含まない現在の合計を計算することは可能ですか?

ROWまたはRANGE引数を使用する必要があると思います。 CURRENT ROWオプションが必要ですが、CURRENT ROW - 1、これは無効な構文です。 ROW引数とRANGE引数についての私の知識は限られているので、どんな助けもありがたく受けられます。

この問題には多くの解決策があることは知っていますが、ROWRANGE引数を理解しようとしています。これらの引数で問題を解読できると思います。以前の現在の合計を計算する1つの可能な方法を含めましたが、もっと良い方法があるかどうか疑問に思います。

USE AdventureWorks2012

SELECT s.SalesOrderID
    , s.SalesOrderDetailID
    , s.OrderQty
    , SUM(s.OrderQty) OVER (PARTITION BY  SalesOrderID) AS RunningTotal
    , SUM(s.OrderQty) OVER (PARTITION BY  SalesOrderID 
                         ORDER BY SalesOrderDetailID) - s.OrderQty AS PreviousRunningTotal
    -- Sudo code - I know this does not work
    --, SUM(s.OrderQty) OVER (PARTITION BY  SalesOrderID 
    --                   ORDER BY SalesOrderDetailID
    --                   ROWS BETWEEN UNBOUNDED PRECEDING 
    --                                   AND CURRENT ROW - 1) 
    -- AS  SudoCodePreviousRunningTotal
FROM Sales.SalesOrderDetail s
WHERE SalesOrderID IN (43670, 43669, 43667, 43663)
ORDER BY s.SalesOrderID
    , s.SalesOrderDetailID 
    , s.OrderQty
15
Steve

答えは、1 PRECEDINGではなくCURRENT ROW -1を使用することです。したがって、クエリでは、次を使用します。

    , SUM(s.OrderQty) OVER (PARTITION BY  SalesOrderID 
                            ORDER BY SalesOrderDetailID
                            ROWS BETWEEN UNBOUNDED PRECEDING 
                                     AND 1 PRECEDING) 
    AS  PreviousRunningTotal

また、他の計算では次のことに注意してください。

    , SUM(s.OrderQty) OVER (PARTITION BY  SalesOrderID
                            ORDER BY SalesOrderDetailID) ...

SQL-Serverはデフォルトを使用します*RANGE UNBOUNDED PRECEDING AND CURRENT ROW。効率の違いがあると思います。ROWS UNBOUNDED PRECEDING AND CURRENT ROWをお勧めします(もちろん、テスト後、必要な結果が得られた場合)。

パフォーマンステストを含む @ Aaron Bertrand によるブログ記事で見つけることができるより多くの詳細:合計を実行するための最良のアプローチ– SQL Server 2012用に更新

* ORDER BYOVER句内に存在する場合、これはもちろんデフォルトの範囲です。それ以外の場合、ORDER BYがないと、デフォルトはパーティション全体になります。

23
ypercubeᵀᴹ