Оконная функция для вычисления объема баланса

#sql #sql-server #tsql #window-functions

#sql #sql-сервер #tsql #окно-функции

Вопрос:

 select a, b, Volume
case
    when lag(a, 1) over(order by b asc) < a then lag(c, 1) over(order by b asc)   Volume
    when lag(a, 1) over(order by b asc) > a then lag(c, 1) over(order by b asc) - Volume
end as c
from Table
 

Итак, чего я хотел бы добиться, так это … если предыдущая a строка больше / меньше текущей a строки, затем добавьте / вычтите Volume из предыдущей строки c .

if a > previous a c = previous c Volume
if a < previous a c = previous c - Volume

Но… c Строки нет, потому что это то, что я вычисляю (поэтому c начальное значение строки равно 0 или NULL) … в нем нет предопределенного набора данных c . Одни данные поступают из другого… вроде того.

Если бы мне пришлось писать это на другом языке, я бы сохранил значение c в отдельной переменной like previousRow и переписывал бы его с каждой итерацией.

Могу ли я добиться аналогичной вещи в TSQL?

Пример данных:

a b Объем c
1 2020-01 10 0
2 2020-02 20 20
5 2020-03 40 60
3 2020-04 30 30
1 2020-05 10 20

Комментарии:

1. Я поместил пример таблицы в вопрос. Код, который я пытаюсь, — это то, что я уже опубликовал. Вот где я застрял.

2. Его можно упорядочить по B (datetimeoffset)

3. @DaleK Вот так: investopedia.com/terms/o/onbalancevolume.asp Найдите формулу в статье

4. Все еще не действительная дата?

5. Я настоятельно рекомендую предоставить DDL DML для создания образца набора данных, чтобы он был полностью понятным.

Ответ №1:

столбец c в значительной степени сводится к условной скользящей сумме, к сожалению, sql server не допускает вложенности оконных функций, поэтому необходима производная таблица для определения предыдущего значения a. После этого суммируйте случай, когда и у вас должно быть то, что вы ищете.

Попробуйте это (добавлены дополнительные тестовые значения к набору, указанному выше):

 SELECT
  T.*,
  SUM(
      (
      CASE
      WHEN T.LAG_A IS NULL
        THEN 0
      WHEN T.A > T.LAG_A 
        THEN T.VOLUME 
        ELSE (T.VOLUME*-1) 
      END
    ) 
  ) OVER (ORDER BY T.B ASC) AS C
FROM
  (
  SELECT                 
    MY_TABLE.A,
    LAG(MY_TABLE.A, 1) OVER (ORDER BY MY_TABLE.B ASC) AS LAG_A,
    MY_TABLE.B,
    MY_TABLE.VOLUME
  FROM
    (VALUES (1,CAST('1/1/2021' AS DATE),10),
            (2,CAST('1/2/2021' AS DATE),20),
            (5,CAST('1/3/2021' AS DATE),40),
            (3,CAST('1/4/2021' AS DATE),30),
            (1,CAST('1/5/2021' AS DATE),10),
            (8,CAST('1/6/2021' AS DATE),50),
            (4,CAST('1/7/2021' AS DATE),70)
    ) AS MY_TABLE(A,B,VOLUME)
  ) T