Suma bieżąca do poprzedniego wiersza

14

Potrzebuję pomocy z funkcjami okienkowania. Wiem, że możesz obliczyć sumę w oknie i sumę bieżącą w oknie. Ale czy można obliczyć poprzednią sumę bieżącą, tj. Sumę bieżącą bez bieżącego wiersza?

Zakładam, że będziesz musiał użyć argumentu ROWlub RANGE. Wiem, że istnieje CURRENT ROWopcja, ale potrzebowałbym CURRENT ROW - 1, która jest niepoprawną składnią. Moja wiedza na temat argumentów ROWi RANGEjest ograniczona, więc każda pomoc byłaby z wdzięcznością przyjęta.

Wiem, że istnieje wiele rozwiązań tego problemu, ale szukam, aby zrozumieć ROW, RANGEargumenty i Zakładam, że problem może być pęknięty z nich. Podałem jeden możliwy sposób obliczenia poprzedniej sumy bieżącej, ale zastanawiam się, czy istnieje lepszy sposób:

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
źródło

Odpowiedzi:

22

Odpowiedź brzmi: 1 PRECEDINGnie używać CURRENT ROW -1. Zatem w zapytaniu użyj:

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

Pamiętaj również, że przy innych obliczeniach:

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

Serwer SQL używa domyślnej * RANGE UNBOUNDED PRECEDING AND CURRENT ROW . Myślę, że istnieje różnica w wydajności i ROWS UNBOUNDED PRECEDING AND CURRENT ROWpowinna być preferowana (po przetestowaniu oczywiście i jeśli daje pożądane wyniki).

Znacznie więcej szczegółów można znaleźć w artykule na blogu autorstwa @Aaron Bertrand , w tym testy wydajności: Najlepsze podejścia do uruchamiania sum - zaktualizowane dla SQL Server 2012

* jest to oczywiście domyślny zakres, gdy ORDER BYw OVERklauzuli występuje an - inaczej bez ORDER BYdomyślnej jest cała partycja.

ypercubeᵀᴹ
źródło