Total acumulado a la fila anterior

14

Necesito ayuda con las funciones de ventanas. Sé que puedes calcular la suma dentro de una ventana y el total acumulado dentro de una ventana. Pero, ¿es posible calcular el total acumulado anterior, es decir, el total acumulado sin incluir la fila actual?

Supongo que necesitarías usar el argumento ROWo RANGE. Sé que hay una CURRENT ROWopción, pero la necesitaría CURRENT ROW - 1, que es una sintaxis no válida. Mi conocimiento de los argumentos ROWy RANGEes limitado, por lo que cualquier ayuda sería recibida con gratitud.

Sé que hay muchas soluciones a este problema, pero estoy en busca de entender los ROW, RANGEargumentos y supongo que el problema puede ser violada con estos. He incluido una forma posible de calcular el total acumulado anterior, pero me pregunto si hay una mejor manera:

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
Steve
fuente

Respuestas:

22

La respuesta es usar 1 PRECEDING, no CURRENT ROW -1. Entonces, en su consulta, use:

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

También tenga en cuenta que en su otro cálculo:

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

SQL-Server utiliza el valor predeterminado * RANGE UNBOUNDED PRECEDING AND CURRENT ROW . Creo que hay una diferencia de eficiencia y ROWS UNBOUNDED PRECEDING AND CURRENT ROWes preferible (después de las pruebas, por supuesto, y si da los resultados que desea).

Puede encontrar muchos más detalles en el artículo del blog de @Aaron Bertrand , incluidas las pruebas de rendimiento: Los mejores enfoques para calcular los totales, actualizados para SQL Server 2012

* este es, por supuesto, el rango predeterminado cuando ORDER BYestá presente un dentro de la OVERcláusula; de lo contrario, sin ORDER BYel valor predeterminado es toda la partición.

ypercubeᵀᴹ
fuente