web-dev-qa-db-fra.com

Total cumulé à la ligne précédente

J'ai besoin d'aide pour les fonctions de fenêtrage. Je sais que vous pouvez calculer la somme dans une fenêtre et le total cumulé dans une fenêtre. Mais est-il possible de calculer le total cumulé précédent, c'est-à-dire le total cumulé hors ligne actuelle?

Je suppose que vous devez utiliser l'argument ROW ou RANGE. Je sais qu'il y a un CURRENT ROW option mais j'aurais besoin de CURRENT ROW - 1, qui n'est pas une syntaxe valide. Ma connaissance des arguments ROW et RANGE étant limitée, toute aide serait reçue avec gratitude.

Je sais qu'il existe de nombreuses solutions à ce problème, mais je cherche à comprendre les arguments ROW, RANGE et je suppose que le problème peut être résolu avec ces derniers. J'ai inclus une façon possible de calculer le total cumulé précédent mais je me demande s'il y a une meilleure façon:

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

La réponse est d'utiliser 1 PRECEDING, ne pas CURRENT ROW -1. Donc, dans votre requête, utilisez:

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

Notez également que sur votre autre calcul:

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

SQL-Server utilise la valeur par défaut *RANGE UNBOUNDED PRECEDING AND CURRENT ROW. Je pense qu'il y a une différence d'efficacité et ROWS UNBOUNDED PRECEDING AND CURRENT ROW est à privilégier (après test bien sûr et s'il donne les résultats souhaités).

Beaucoup plus de détails que vous pouvez trouver dans l'article de blog par @ Aaron Bertrand , y compris les tests de performances: Meilleures approches pour l'exécution des totaux - mis à jour pour SQL Server 2012

* c'est bien sûr la plage par défaut quand un ORDER BY est présent dans la clause OVER - sinon, sans ORDER BY la valeur par défaut est toute la partition.

23
ypercubeᵀᴹ