Подведение итогов к предыдущему ряду

14

Мне нужна помощь с оконными функциями. Я знаю, что вы можете рассчитать сумму в окне и промежуточную сумму в окне. Но возможно ли рассчитать предыдущий промежуточный итог, т.е. промежуточный итог, не включая текущую строку?

Я предполагаю, что вам нужно будет использовать аргумент ROWили RANGE. Я знаю, что есть CURRENT ROWопция, но мне нужно CURRENT ROW - 1, это неверный синтаксис. Мои знания аргументов ROWand RANGEограничены, поэтому любая помощь будет принята с благодарностью.

Я знаю, что есть много решений этой проблемы, но я хочу понять ROW, RANGEаргументы, и я предполагаю, что проблема может быть решена с их помощью. Я включил один из возможных способов расчета предыдущей промежуточной суммы, но мне интересно, есть ли лучший способ:

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
Стив
источник

Ответы:

22

Ответ заключается в использовании 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-сервер использует по умолчанию * RANGE UNBOUNDED PRECEDING AND CURRENT ROW . Я думаю, что есть разница в эффективности, и ROWS UNBOUNDED PRECEDING AND CURRENT ROWее следует отдавать предпочтение (после тестирования, конечно, и если оно даст желаемые результаты).

Более подробную информацию вы можете найти в статье блога @Aaron Bertrand , включая тесты производительности: лучшие подходы к подведению итогов - обновлено для SQL Server 2012

* это, конечно, диапазон по умолчанию, когда в предложении ORDER BYприсутствует an OVER- иначе, ORDER BYпо умолчанию без целого раздела.

ypercubeᵀᴹ
источник