Total em execução para a linha anterior

14

Preciso de ajuda com as funções de janelas. Eu sei que você pode calcular a soma dentro de uma janela e o total em execução dentro de uma janela. Mas é possível calcular o total de corrida anterior, ou seja, o total de corrida que não inclui a linha atual?

Eu suponho que você precisaria usar o ROWou RANGEargumento. Eu sei que existe uma CURRENT ROWopção, mas eu precisaria CURRENT ROW - 1, que é uma sintaxe inválida. Meu conhecimento dos argumentos ROWe RANGEé limitado, portanto qualquer ajuda seria recebida com gratidão.

Eu sei que existem muitas soluções para este problema, mas eu estou olhando para compreender as ROW, RANGEargumentos e presumo que o problema pode ser quebrada com estes. Incluí uma maneira possível de calcular o total anterior, mas me pergunto se existe uma maneira melhor:

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
fonte

Respostas:

22

A resposta é usar 1 PRECEDING, não CURRENT ROW -1. Portanto, na sua consulta, use:

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

Observe também que em seu outro cálculo:

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

O SQL-Server usa o padrão * RANGE UNBOUNDED PRECEDING AND CURRENT ROW . Eu acho que há uma diferença de eficiência e ROWS UNBOUNDED PRECEDING AND CURRENT ROWdeve ser preferida (após o teste, é claro, e se der os resultados desejados).

Muito mais detalhes você pode encontrar no artigo de blog de @Aaron Bertrand , incluindo testes de desempenho: Melhores abordagens para execução de totais - atualizadas para o SQL Server 2012

* é claro que este é o intervalo padrão quando um ORDER BYestá presente dentro da OVERcláusula - caso contrário, sem ORDER BYo padrão é toda a partição.

ypercubeᵀᴹ
fonte